diff --git a/.eslintcache b/.eslintcache index 178f192..cbe4e16 100644 --- a/.eslintcache +++ b/.eslintcache @@ -1 +1 @@ -[{"/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Cohort.ts":"1","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/CohortInterfaces.ts":"2","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/CohortRepresentations.ts":"3","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/OnboardingManager.ts":"4","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Overview/CohortOverview.ts":"5","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Overview/OverviewLayout.ts":"6","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Overview/index.ts":"7","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Provenance/CohortEV.ts":"8","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Provenance/General.ts":"9","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/TaskRepresentations.ts":"10","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Tasks.ts":"11","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/SearchBar.ts":"12","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/SearchColumn.ts":"13","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/Taskview.ts":"14","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/columns/AColumn.ts":"15","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/columns/AttributeColumn.ts":"16","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/columns/CohortColumn.ts":"17","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/columns/NumberColumn.ts":"18","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/columns/PrevalenceColumn.ts":"19","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/columns/index.ts":"20","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/index.ts":"21","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/tasks/ATask.ts":"22","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/tasks/Compare.ts":"23","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/tasks/Details.ts":"24","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/tasks/Filter.ts":"25","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/tasks/Prevalence.ts":"26","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/tasks/TaskList.ts":"27","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/tasks/index.ts":"28","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/AVegaVisualization.ts":"29","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/AreaChart.ts":"30","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/DensityPlot.ts":"31","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/GroupedBoxplot.ts":"32","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/GroupedHistogram.ts":"33","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/Histogram.ts":"34","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/IVisualization.ts":"35","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/KaplanMeierPlot.ts":"36","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/MultiAttributeVisualization.ts":"37","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/Scatterplot.ts":"38","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/config/ConfidenceConfig.ts":"39","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/config/CountCounfig.ts":"40","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/config/GroupConfig.ts":"41","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/config/ScaleConfig.ts":"42","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/config/SortConfig.ts":"43","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/config/VisConfig.ts":"44","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/constants.ts":"45","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/dimreduce/OneHotEncoder.ts":"46","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/dimreduce/OneHotEncoder.worker.ts":"47","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/dimreduce/tsne.worker.ts":"48","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/index.ts":"49","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Tooltip.ts":"50","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/app.ts":"51","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/base/extensions.ts":"52","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/cohortview.ts":"53","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/colors.ts":"54","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/common/GeneUtils.ts":"55","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/common/config.ts":"56","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/common/forms.ts":"57","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/common/index.ts":"58","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/config/onboarding.ts":"59","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/data/Attribute.ts":"60","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/data/SpecialAttribute.ts":"61","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/data/index.ts":"62","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/index.ts":"63","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/phovea.ts":"64","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/phovea_registry.ts":"65","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/rest.ts":"66","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/util.ts":"67","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/utilCustomEvents.ts":"68","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/utilIdTypes.ts":"69","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/utilLabels.ts":"70","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/utils/RouterScrollToTop.tsx":"71","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/utils/index.ts":"72","/home/runner/work/github-maintenance/github-maintenance/tmp/repository/tests/app.test.ts":"73"},{"size":27212,"mtime":1660653050518},{"size":4277,"mtime":1660653050498},{"size":26818,"mtime":1660653050514},{"size":1502,"mtime":1660653050514},{"size":43468,"mtime":1660653050514},{"size":8116,"mtime":1660653050518},{"size":68,"mtime":1660653050514,"results":"74","hashOfConfig":"75"},{"size":3224,"mtime":1660653050522},{"size":1789,"mtime":1660653050522},{"size":5525,"mtime":1660653050514},{"size":5954,"mtime":1660653050522},{"size":42678,"mtime":1660653050522},{"size":6077,"mtime":1660653050522},{"size":24877,"mtime":1660653050522},{"size":6881,"mtime":1660653050518},{"size":17186,"mtime":1660653050518},{"size":3801,"mtime":1660653050518},{"size":1098,"mtime":1660653050518},{"size":4135,"mtime":1660653050518},{"size":344,"mtime":1660653050518},{"size":280,"mtime":1660653050518},{"size":2224,"mtime":1660653050522},{"size":28965,"mtime":1660653050522},{"size":6579,"mtime":1660653050522},{"size":9719,"mtime":1660653050522},{"size":42107,"mtime":1660653050522},{"size":319,"mtime":1660653050522},{"size":163,"mtime":1660653050522,"results":"76","hashOfConfig":"75"},{"size":31993,"mtime":1660653050518},{"size":3175,"mtime":1660653050518},{"size":20420,"mtime":1660653050518},{"size":45017,"mtime":1660653050518},{"size":8895,"mtime":1660653050518},{"size":5455,"mtime":1660653050518},{"size":411,"mtime":1660653050518},{"size":32290,"mtime":1660653050518},{"size":20281,"mtime":1660653050518},{"size":39002,"mtime":1660653050522},{"size":315,"mtime":1660653050518},{"size":272,"mtime":1660653050518},{"size":433,"mtime":1660653050518},{"size":631,"mtime":1660653050518},{"size":835,"mtime":1660653050518},{"size":1049,"mtime":1660653050518},{"size":173,"mtime":1660653050518},{"size":2820,"mtime":1660653050518},{"size":115,"mtime":1660653050518},{"size":95,"mtime":1660653050518},{"size":304,"mtime":1660653050518,"results":"77","hashOfConfig":"75"},{"size":2776,"mtime":1660653050514},{"size":26865,"mtime":1660653050518},{"size":838,"mtime":1660653050498},{"size":2595,"mtime":1660653050498},{"size":417,"mtime":1660653050514},{"size":8349,"mtime":1660653050498},{"size":17683,"mtime":1660653050498},{"size":24505,"mtime":1660653050498},{"size":80,"mtime":1660653050498,"results":"78","hashOfConfig":"75"},{"size":4306,"mtime":1660653050514},{"size":19692,"mtime":1660653050514},{"size":16041,"mtime":1660653050514},{"size":29,"mtime":1660653050514,"results":"79","hashOfConfig":"75"},{"size":311,"mtime":1660653050514,"results":"80","hashOfConfig":"75"},{"size":2685,"mtime":1660653050522},{"size":617,"mtime":1660653050534},{"size":23209,"mtime":1660653050518},{"size":9294,"mtime":1660653050498},{"size":3931,"mtime":1660653050514},{"size":1968,"mtime":1660653050498},{"size":9552,"mtime":1660653050498},{"size":358,"mtime":1660653050518,"results":"81","hashOfConfig":"75"},{"size":37,"mtime":1660653050518,"results":"82","hashOfConfig":"75"},{"size":280,"mtime":1660653046218,"results":"83","hashOfConfig":"75"},{"filePath":"84","messages":"85","suppressedMessages":"86","errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},"2udmpj",{"filePath":"87","messages":"88","suppressedMessages":"89","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"90","messages":"91","suppressedMessages":"92","errorCount":8,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"93","messages":"94","suppressedMessages":"95","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"96","messages":"97","suppressedMessages":"98","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"99","messages":"100","suppressedMessages":"101","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"102","messages":"103","suppressedMessages":"104","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"105","messages":"106","suppressedMessages":"107","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"108","messages":"109","suppressedMessages":"110","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},"/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Overview/index.ts",["111","112"],[],"/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/tasks/index.ts",[],[],"/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/Taskview/visualizations/index.ts",["113","114","115","116","117","118","119","120"],[],"/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/common/index.ts",[],[],"/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/data/index.ts",[],[],"/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/index.ts",[],[],"/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/utils/RouterScrollToTop.tsx",[],[],"/home/runner/work/github-maintenance/github-maintenance/tmp/repository/src/utils/index.ts",[],[],"/home/runner/work/github-maintenance/github-maintenance/tmp/repository/tests/app.test.ts",["121","122"],[],{"ruleId":"123","severity":2,"message":"124","line":1,"column":1,"nodeType":"125","endLine":1,"endColumn":34},{"ruleId":"123","severity":2,"message":"126","line":2,"column":1,"nodeType":"125","endLine":2,"endColumn":34},{"ruleId":"123","severity":2,"message":"127","line":1,"column":1,"nodeType":"125","endLine":1,"endColumn":29},{"ruleId":"123","severity":2,"message":"128","line":2,"column":1,"nodeType":"125","endLine":2,"endColumn":38},{"ruleId":"123","severity":2,"message":"129","line":4,"column":1,"nodeType":"125","endLine":4,"endColumn":31},{"ruleId":"123","severity":2,"message":"130","line":5,"column":1,"nodeType":"125","endLine":5,"endColumn":36},{"ruleId":"123","severity":2,"message":"131","line":6,"column":1,"nodeType":"125","endLine":6,"endColumn":29},{"ruleId":"123","severity":2,"message":"132","line":7,"column":1,"nodeType":"125","endLine":7,"endColumn":34},{"ruleId":"123","severity":2,"message":"133","line":8,"column":1,"nodeType":"125","endLine":8,"endColumn":47},{"ruleId":"123","severity":2,"message":"134","line":9,"column":1,"nodeType":"125","endLine":9,"endColumn":31},{"ruleId":"135","severity":1,"message":"136","line":10,"column":1,"nodeType":"137","messageId":"138","endLine":10,"endColumn":30},{"ruleId":"135","severity":1,"message":"136","line":11,"column":1,"nodeType":"137","messageId":"138","endLine":11,"endColumn":29},"import/no-cycle","Dependency cycle via ../app:4","ExportAllDeclaration","Dependency cycle via ../CohortInterfaces:1=>./data/Attribute:4=>./SpecialAttribute:9=>../cohortview:4=>./app:3","Dependency cycle via ../../CohortInterfaces:4=>./Taskview/Taskview:6=>./SearchColumn:11=>./tasks/TaskList:10=>./Details:3","Dependency cycle via ../../CohortInterfaces:9=>./Taskview/Taskview:6=>./SearchColumn:11=>./tasks/TaskList:10=>./Details:3","Dependency cycle via ../../CohortInterfaces:6=>./Taskview/Taskview:6=>./SearchColumn:11=>./tasks/TaskList:10=>./Details:3","Dependency cycle via ../../CohortInterfaces:5=>./Taskview/Taskview:6=>./SearchColumn:11=>./tasks/TaskList:10=>./Details:3","Dependency cycle via ../../CohortInterfaces:2=>./Taskview/Taskview:6=>./SearchColumn:11=>./tasks/TaskList:10=>./Details:3","Dependency cycle via ../../CohortInterfaces:1=>./Taskview/Taskview:6=>./SearchColumn:11=>./tasks/TaskList:10=>./Details:3","Dependency cycle via ../../CohortInterfaces:8=>./Taskview/Taskview:6=>./SearchColumn:11=>./tasks/TaskList:10=>./Details:3","Dependency cycle via ../../Cohort:5=>./CohortInterfaces:2=>./Taskview/Taskview:6=>./SearchColumn:11=>./tasks/TaskList:10=>./Details:3","jest/no-commented-out-tests","Some tests seem to be commented","Line","commentedTests"] \ No newline at end of file +[{"/home/oltion/workspaces/coral/coral/coral/src/Cohort.ts":"1","/home/oltion/workspaces/coral/coral/coral/src/CohortContext.ts":"2","/home/oltion/workspaces/coral/coral/coral/src/CohortRepresentations.ts":"3","/home/oltion/workspaces/coral/coral/coral/src/OnboardingManager.ts":"4","/home/oltion/workspaces/coral/coral/coral/src/Overview/CohortOverview.ts":"5","/home/oltion/workspaces/coral/coral/coral/src/Overview/OverviewLayout.ts":"6","/home/oltion/workspaces/coral/coral/coral/src/Overview/index.ts":"7","/home/oltion/workspaces/coral/coral/coral/src/Provenance/CohortEV.ts":"8","/home/oltion/workspaces/coral/coral/coral/src/Provenance/General.ts":"9","/home/oltion/workspaces/coral/coral/coral/src/TaskRepresentations.ts":"10","/home/oltion/workspaces/coral/coral/coral/src/Tasks.ts":"11","/home/oltion/workspaces/coral/coral/coral/src/Taskview/SearchBar.ts":"12","/home/oltion/workspaces/coral/coral/coral/src/Taskview/SearchColumn.ts":"13","/home/oltion/workspaces/coral/coral/coral/src/Taskview/Taskview.ts":"14","/home/oltion/workspaces/coral/coral/coral/src/Taskview/columns/AColumn.ts":"15","/home/oltion/workspaces/coral/coral/coral/src/Taskview/columns/AttributeColumn.ts":"16","/home/oltion/workspaces/coral/coral/coral/src/Taskview/columns/CohortColumn.ts":"17","/home/oltion/workspaces/coral/coral/coral/src/Taskview/columns/NumberColumn.ts":"18","/home/oltion/workspaces/coral/coral/coral/src/Taskview/columns/PrevalenceColumn.ts":"19","/home/oltion/workspaces/coral/coral/coral/src/Taskview/columns/index.ts":"20","/home/oltion/workspaces/coral/coral/coral/src/Taskview/index.ts":"21","/home/oltion/workspaces/coral/coral/coral/src/Taskview/interfaces.ts":"22","/home/oltion/workspaces/coral/coral/coral/src/Taskview/tasks/ATask.ts":"23","/home/oltion/workspaces/coral/coral/coral/src/Taskview/tasks/Compare.ts":"24","/home/oltion/workspaces/coral/coral/coral/src/Taskview/tasks/Details.ts":"25","/home/oltion/workspaces/coral/coral/coral/src/Taskview/tasks/Filter.ts":"26","/home/oltion/workspaces/coral/coral/coral/src/Taskview/tasks/Prevalence.ts":"27","/home/oltion/workspaces/coral/coral/coral/src/Taskview/tasks/TaskList.ts":"28","/home/oltion/workspaces/coral/coral/coral/src/Taskview/tasks/index.ts":"29","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/AVegaVisualization.ts":"30","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/AreaChart.ts":"31","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/DensityPlot.ts":"32","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/GroupedBoxplot.ts":"33","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/GroupedHistogram.ts":"34","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/Histogram.ts":"35","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/IVisualization.ts":"36","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/KaplanMeierPlot.ts":"37","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/MultiAttributeVisualization.ts":"38","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/Scatterplot.ts":"39","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/config/ConfidenceConfig.ts":"40","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/config/CountCounfig.ts":"41","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/config/GroupConfig.ts":"42","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/config/ScaleConfig.ts":"43","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/config/SortConfig.ts":"44","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/config/VisConfig.ts":"45","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/constants.ts":"46","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/dimreduce/OneHotEncoder.ts":"47","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/dimreduce/OneHotEncoder.worker.ts":"48","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/dimreduce/tsne.worker.ts":"49","/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/index.ts":"50","/home/oltion/workspaces/coral/coral/coral/src/app/Coral.ts":"51","/home/oltion/workspaces/coral/coral/coral/src/app/CoralApp.ts":"52","/home/oltion/workspaces/coral/coral/coral/src/app/CoralSelectionListener.ts":"53","/home/oltion/workspaces/coral/coral/coral/src/app/index.ts":"54","/home/oltion/workspaces/coral/coral/coral/src/app/interfaces.ts":"55","/home/oltion/workspaces/coral/coral/coral/src/base/events.ts":"56","/home/oltion/workspaces/coral/coral/coral/src/base/extensions.ts":"57","/home/oltion/workspaces/coral/coral/coral/src/base/index.ts":"58","/home/oltion/workspaces/coral/coral/coral/src/base/interfaces.ts":"59","/home/oltion/workspaces/coral/coral/coral/src/base/rest.ts":"60","/home/oltion/workspaces/coral/coral/coral/src/cohortview.ts":"61","/home/oltion/workspaces/coral/coral/coral/src/common/GeneUtils.ts":"62","/home/oltion/workspaces/coral/coral/coral/src/common/config.ts":"63","/home/oltion/workspaces/coral/coral/coral/src/common/forms.ts":"64","/home/oltion/workspaces/coral/coral/coral/src/common/index.ts":"65","/home/oltion/workspaces/coral/coral/coral/src/config/colors.ts":"66","/home/oltion/workspaces/coral/coral/coral/src/config/entities.ts":"67","/home/oltion/workspaces/coral/coral/coral/src/config/onboarding.ts":"68","/home/oltion/workspaces/coral/coral/coral/src/data/Attribute.ts":"69","/home/oltion/workspaces/coral/coral/coral/src/data/IAttribute.ts":"70","/home/oltion/workspaces/coral/coral/coral/src/data/ISpecialAttribute.ts":"71","/home/oltion/workspaces/coral/coral/coral/src/data/SpecialAttribute.ts":"72","/home/oltion/workspaces/coral/coral/coral/src/data/index.ts":"73","/home/oltion/workspaces/coral/coral/coral/src/index.ts":"74","/home/oltion/workspaces/coral/coral/coral/src/phovea.ts":"75","/home/oltion/workspaces/coral/coral/coral/src/phovea_registry.ts":"76","/home/oltion/workspaces/coral/coral/coral/src/util.ts":"77","/home/oltion/workspaces/coral/coral/coral/src/utils/RouterScrollToTop.tsx":"78","/home/oltion/workspaces/coral/coral/coral/src/utils/ScrollLinker.ts":"79","/home/oltion/workspaces/coral/coral/coral/src/utils/index.ts":"80","/home/oltion/workspaces/coral/coral/coral/src/utils/labels.ts":"81","/home/oltion/workspaces/coral/coral/coral/tests/app.test.ts":"82","/home/oltion/workspaces/coral/latest/coral/coral/src/Cohort.ts":"83","/home/oltion/workspaces/coral/latest/coral/coral/src/CohortContext.ts":"84","/home/oltion/workspaces/coral/latest/coral/coral/src/CohortRepresentations.ts":"85","/home/oltion/workspaces/coral/latest/coral/coral/src/OnboardingManager.ts":"86","/home/oltion/workspaces/coral/latest/coral/coral/src/Overview/CohortOverview.ts":"87","/home/oltion/workspaces/coral/latest/coral/coral/src/Overview/OverviewLayout.ts":"88","/home/oltion/workspaces/coral/latest/coral/coral/src/Overview/index.ts":"89","/home/oltion/workspaces/coral/latest/coral/coral/src/Provenance/CohortEV.ts":"90","/home/oltion/workspaces/coral/latest/coral/coral/src/Provenance/General.ts":"91","/home/oltion/workspaces/coral/latest/coral/coral/src/TaskRepresentations.ts":"92","/home/oltion/workspaces/coral/latest/coral/coral/src/Tasks.ts":"93","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/SearchBar.ts":"94","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/SearchColumn.ts":"95","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/Taskview.ts":"96","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/columns/AColumn.ts":"97","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/columns/AttributeColumn.ts":"98","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/columns/CohortColumn.ts":"99","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/columns/Histogram.ts":"100","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/columns/NumberColumn.ts":"101","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/columns/PrevalenceColumn.ts":"102","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/columns/index.ts":"103","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/index.ts":"104","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/interfaces.ts":"105","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/tasks/ATask.ts":"106","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/tasks/Compare.ts":"107","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/tasks/Details.ts":"108","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/tasks/Filter.ts":"109","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/tasks/Prevalence.ts":"110","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/tasks/TaskList.ts":"111","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/tasks/index.ts":"112","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/AVegaVisualization.ts":"113","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/AreaChart.ts":"114","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/DensityPlot.ts":"115","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/GroupedBoxplot.ts":"116","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/GroupedHistogram.ts":"117","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/Histogram.ts":"118","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/IVisualization.ts":"119","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/KaplanMeierPlot.ts":"120","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/MultiAttributeVisualization.ts":"121","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/Scatterplot.ts":"122","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/config/ConfidenceConfig.ts":"123","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/config/CountCounfig.ts":"124","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/config/GroupConfig.ts":"125","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/config/ScaleConfig.ts":"126","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/config/SortConfig.ts":"127","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/config/VisConfig.ts":"128","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/constants.ts":"129","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/dimreduce/OneHotEncoder.ts":"130","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/dimreduce/OneHotEncoder.worker.ts":"131","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/dimreduce/tsne.worker.ts":"132","/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/index.ts":"133","/home/oltion/workspaces/coral/latest/coral/coral/src/app/Coral.ts":"134","/home/oltion/workspaces/coral/latest/coral/coral/src/app/CoralApp.ts":"135","/home/oltion/workspaces/coral/latest/coral/coral/src/app/CoralSelectionListener.ts":"136","/home/oltion/workspaces/coral/latest/coral/coral/src/app/index.ts":"137","/home/oltion/workspaces/coral/latest/coral/coral/src/app/interfaces.ts":"138","/home/oltion/workspaces/coral/latest/coral/coral/src/base/events.ts":"139","/home/oltion/workspaces/coral/latest/coral/coral/src/base/extensions.ts":"140","/home/oltion/workspaces/coral/latest/coral/coral/src/base/index.ts":"141","/home/oltion/workspaces/coral/latest/coral/coral/src/base/interfaces.ts":"142","/home/oltion/workspaces/coral/latest/coral/coral/src/base/rest.ts":"143","/home/oltion/workspaces/coral/latest/coral/coral/src/cohortview.ts":"144","/home/oltion/workspaces/coral/latest/coral/coral/src/common/GeneUtils.ts":"145","/home/oltion/workspaces/coral/latest/coral/coral/src/common/config.ts":"146","/home/oltion/workspaces/coral/latest/coral/coral/src/common/forms.ts":"147","/home/oltion/workspaces/coral/latest/coral/coral/src/common/index.ts":"148","/home/oltion/workspaces/coral/latest/coral/coral/src/config/colors.ts":"149","/home/oltion/workspaces/coral/latest/coral/coral/src/config/entities.ts":"150","/home/oltion/workspaces/coral/latest/coral/coral/src/config/onboarding.ts":"151","/home/oltion/workspaces/coral/latest/coral/coral/src/data/Attribute.ts":"152","/home/oltion/workspaces/coral/latest/coral/coral/src/data/IAttribute.ts":"153","/home/oltion/workspaces/coral/latest/coral/coral/src/data/ISpecialAttribute.ts":"154","/home/oltion/workspaces/coral/latest/coral/coral/src/data/SpecialAttribute.ts":"155","/home/oltion/workspaces/coral/latest/coral/coral/src/data/index.ts":"156","/home/oltion/workspaces/coral/latest/coral/coral/src/index.ts":"157","/home/oltion/workspaces/coral/latest/coral/coral/src/phovea.ts":"158","/home/oltion/workspaces/coral/latest/coral/coral/src/phovea_registry.ts":"159","/home/oltion/workspaces/coral/latest/coral/coral/src/util.ts":"160","/home/oltion/workspaces/coral/latest/coral/coral/src/utils/RouterScrollToTop.tsx":"161","/home/oltion/workspaces/coral/latest/coral/coral/src/utils/ScrollLinker.ts":"162","/home/oltion/workspaces/coral/latest/coral/coral/src/utils/index.ts":"163","/home/oltion/workspaces/coral/latest/coral/coral/src/utils/labels.ts":"164","/home/oltion/workspaces/coral/latest/coral/coral/tests/app.test.ts":"165"},{"size":28962,"mtime":1677750080609,"results":"166","hashOfConfig":"167"},{"size":336,"mtime":1677762336104,"results":"168","hashOfConfig":"167"},{"size":26927,"mtime":1677762386064,"results":"169","hashOfConfig":"167"},{"size":1471,"mtime":1677752771124,"results":"170","hashOfConfig":"167"},{"size":43451,"mtime":1677758519960,"results":"171","hashOfConfig":"167"},{"size":8036,"mtime":1677674925077,"results":"172","hashOfConfig":"167"},{"size":68,"mtime":1677147981823,"results":"173","hashOfConfig":"167"},{"size":3364,"mtime":1677758572696,"results":"174","hashOfConfig":"167"},{"size":1843,"mtime":1677758627448,"results":"175","hashOfConfig":"167"},{"size":5511,"mtime":1677674925077,"results":"176","hashOfConfig":"167"},{"size":4045,"mtime":1677752741909,"results":"177","hashOfConfig":"167"},{"size":41779,"mtime":1677757663852,"results":"178","hashOfConfig":"167"},{"size":6210,"mtime":1677758743755,"results":"179","hashOfConfig":"167"},{"size":24769,"mtime":1677759334028,"results":"180","hashOfConfig":"167"},{"size":9665,"mtime":1677757712484,"results":"181","hashOfConfig":"167"},{"size":17420,"mtime":1677757934638,"results":"182","hashOfConfig":"167"},{"size":3816,"mtime":1677674925077,"results":"183","hashOfConfig":"167"},{"size":1110,"mtime":1677674925077,"results":"184","hashOfConfig":"167"},{"size":4187,"mtime":1677674925077,"results":"185","hashOfConfig":"167"},{"size":247,"mtime":1677758031466,"results":"186","hashOfConfig":"167"},{"size":284,"mtime":1677147981823,"results":"187","hashOfConfig":"167"},{"size":0,"mtime":1677752754957,"results":"188","hashOfConfig":"167"},{"size":2236,"mtime":1677750630495,"results":"189","hashOfConfig":"167"},{"size":29374,"mtime":1677750892903,"results":"190","hashOfConfig":"167"},{"size":6615,"mtime":1677751116446,"results":"191","hashOfConfig":"167"},{"size":9903,"mtime":1677759432283,"results":"192","hashOfConfig":"167"},{"size":42231,"mtime":1677758809951,"results":"193","hashOfConfig":"167"},{"size":319,"mtime":1677147981823,"results":"194","hashOfConfig":"167"},{"size":163,"mtime":1677147981823,"results":"195","hashOfConfig":"167"},{"size":32721,"mtime":1677758979138,"results":"196","hashOfConfig":"167"},{"size":3205,"mtime":1677758924402,"results":"197","hashOfConfig":"167"},{"size":20498,"mtime":1677759042594,"results":"198","hashOfConfig":"167"},{"size":45715,"mtime":1677759084225,"results":"199","hashOfConfig":"167"},{"size":9381,"mtime":1677759101049,"results":"200","hashOfConfig":"167"},{"size":5511,"mtime":1677674925077,"results":"201","hashOfConfig":"167"},{"size":426,"mtime":1677762573739,"results":"202","hashOfConfig":"167"},{"size":32067,"mtime":1677762580106,"results":"203","hashOfConfig":"167"},{"size":20476,"mtime":1677759285868,"results":"204","hashOfConfig":"167"},{"size":40013,"mtime":1677759259572,"results":"205","hashOfConfig":"167"},{"size":316,"mtime":1677147981827,"results":"206","hashOfConfig":"167"},{"size":273,"mtime":1677147981827,"results":"207","hashOfConfig":"167"},{"size":435,"mtime":1677147981827,"results":"208","hashOfConfig":"167"},{"size":633,"mtime":1677147981827,"results":"209","hashOfConfig":"167"},{"size":848,"mtime":1677147981827,"results":"210","hashOfConfig":"167"},{"size":1047,"mtime":1677147981827,"results":"211","hashOfConfig":"167"},{"size":171,"mtime":1677147981827,"results":"212","hashOfConfig":"167"},{"size":2871,"mtime":1677147981827,"results":"213","hashOfConfig":"167"},{"size":117,"mtime":1677147981827,"results":"214","hashOfConfig":"167"},{"size":97,"mtime":1677147981827,"results":"215","hashOfConfig":"167"},{"size":304,"mtime":1677147981827,"results":"216","hashOfConfig":"167"},{"size":1873,"mtime":1677674925077,"results":"217","hashOfConfig":"167"},{"size":22713,"mtime":1677762243073,"results":"218","hashOfConfig":"167"},{"size":3141,"mtime":1677759409836,"results":"219","hashOfConfig":"167"},{"size":125,"mtime":1677674925077,"results":"220","hashOfConfig":"167"},{"size":6846,"mtime":1677675318586,"results":"221","hashOfConfig":"167"},{"size":4006,"mtime":1677757813027,"results":"222","hashOfConfig":"167"},{"size":842,"mtime":1677147981835,"results":"223","hashOfConfig":"167"},{"size":54,"mtime":1677678106347,"results":"224","hashOfConfig":"167"},{"size":6542,"mtime":1677757948254,"results":"225","hashOfConfig":"167"},{"size":17405,"mtime":1677679749229,"results":"226","hashOfConfig":"167"},{"size":2522,"mtime":1677762480963,"results":"227","hashOfConfig":"167"},{"size":8357,"mtime":1677147981835,"results":"228","hashOfConfig":"167"},{"size":16562,"mtime":1677674999908,"results":"229","hashOfConfig":"167"},{"size":22691,"mtime":1677674999908,"results":"230","hashOfConfig":"167"},{"size":80,"mtime":1677147981835,"results":"231","hashOfConfig":"167"},{"size":1226,"mtime":1677674925081,"results":"232","hashOfConfig":"167"},{"size":1974,"mtime":1677674925081,"results":"233","hashOfConfig":"167"},{"size":4314,"mtime":1677147981835,"results":"234","hashOfConfig":"167"},{"size":16586,"mtime":1677750630495,"results":"235","hashOfConfig":"167"},{"size":3220,"mtime":1677679815813,"results":"236","hashOfConfig":"167"},{"size":1522,"mtime":1677750630495,"results":"237","hashOfConfig":"167"},{"size":15086,"mtime":1677750630495,"results":"238","hashOfConfig":"167"},{"size":59,"mtime":1677750661147,"results":"239","hashOfConfig":"167"},{"size":298,"mtime":1677678138579,"results":"240","hashOfConfig":"167"},{"size":2725,"mtime":1677674999908,"results":"241","hashOfConfig":"167"},{"size":660,"mtime":1677674999908,"results":"242","hashOfConfig":"167"},{"size":8905,"mtime":1677759231461,"results":"243","hashOfConfig":"167"},{"size":358,"mtime":1677674925081,"results":"244","hashOfConfig":"167"},{"size":1214,"mtime":1677674925081,"results":"245","hashOfConfig":"167"},{"size":37,"mtime":1677674925081,"results":"246","hashOfConfig":"167"},{"size":9496,"mtime":1677759126833,"results":"247","hashOfConfig":"167"},{"size":280,"mtime":1677147981835,"results":"248","hashOfConfig":"167"},{"size":29023,"mtime":1678699151981,"results":"249","hashOfConfig":"250"},{"size":402,"mtime":1678699060173,"results":"251","hashOfConfig":"250"},{"size":26970,"mtime":1678699060173,"results":"252","hashOfConfig":"250"},{"size":1547,"mtime":1678699060173,"results":"253","hashOfConfig":"250"},{"size":43451,"mtime":1678699060173,"results":"254","hashOfConfig":"250"},{"size":8036,"mtime":1678699060173,"results":"255","hashOfConfig":"250"},{"size":68,"mtime":1678269004673,"results":"256","hashOfConfig":"250"},{"size":3425,"mtime":1678699060173,"results":"257","hashOfConfig":"250"},{"size":1915,"mtime":1678699060173,"results":"258","hashOfConfig":"250"},{"size":5511,"mtime":1678699060173,"results":"259","hashOfConfig":"250"},{"size":4047,"mtime":1678699060173,"results":"260","hashOfConfig":"250"},{"size":41942,"mtime":1678699170820,"results":"261","hashOfConfig":"250"},{"size":6298,"mtime":1678699060173,"results":"262","hashOfConfig":"250"},{"size":25131,"mtime":1678699060173,"results":"263","hashOfConfig":"250"},{"size":9796,"mtime":1678699060173,"results":"264","hashOfConfig":"250"},{"size":5694,"mtime":1678699060173,"results":"265","hashOfConfig":"250"},{"size":3816,"mtime":1678699060173,"results":"266","hashOfConfig":"250"},{"size":11992,"mtime":1678699060173,"results":"267","hashOfConfig":"250"},{"size":1110,"mtime":1678699060173,"results":"268","hashOfConfig":"250"},{"size":4252,"mtime":1678699060173,"results":"269","hashOfConfig":"250"},{"size":247,"mtime":1678699060173,"results":"270","hashOfConfig":"250"},{"size":224,"mtime":1678699060173,"results":"271","hashOfConfig":"250"},{"size":0,"mtime":1678699060173,"results":"272","hashOfConfig":"250"},{"size":2370,"mtime":1678699060173,"results":"273","hashOfConfig":"250"},{"size":29759,"mtime":1678699060173,"results":"274","hashOfConfig":"250"},{"size":6448,"mtime":1678699060173,"results":"275","hashOfConfig":"250"},{"size":9903,"mtime":1678699060173,"results":"276","hashOfConfig":"250"},{"size":42407,"mtime":1678699060173,"results":"277","hashOfConfig":"250"},{"size":319,"mtime":1678269004673,"results":"278","hashOfConfig":"250"},{"size":163,"mtime":1678269004673,"results":"279","hashOfConfig":"250"},{"size":32682,"mtime":1678699060173,"results":"280","hashOfConfig":"250"},{"size":3205,"mtime":1678699060173,"results":"281","hashOfConfig":"250"},{"size":20444,"mtime":1678699060173,"results":"282","hashOfConfig":"250"},{"size":45783,"mtime":1678699060173,"results":"283","hashOfConfig":"250"},{"size":9381,"mtime":1678699060173,"results":"284","hashOfConfig":"250"},{"size":5512,"mtime":1678699060173,"results":"285","hashOfConfig":"250"},{"size":426,"mtime":1678699060173,"results":"286","hashOfConfig":"250"},{"size":32149,"mtime":1678699060173,"results":"287","hashOfConfig":"250"},{"size":20640,"mtime":1678699060173,"results":"288","hashOfConfig":"250"},{"size":40145,"mtime":1678699060173,"results":"289","hashOfConfig":"250"},{"size":316,"mtime":1678269004673,"results":"290","hashOfConfig":"250"},{"size":273,"mtime":1678269004673,"results":"291","hashOfConfig":"250"},{"size":435,"mtime":1678269004673,"results":"292","hashOfConfig":"250"},{"size":633,"mtime":1678269004673,"results":"293","hashOfConfig":"250"},{"size":848,"mtime":1678269004673,"results":"294","hashOfConfig":"250"},{"size":1047,"mtime":1678269004673,"results":"295","hashOfConfig":"250"},{"size":171,"mtime":1678269004673,"results":"296","hashOfConfig":"250"},{"size":2866,"mtime":1678699060173,"results":"297","hashOfConfig":"250"},{"size":117,"mtime":1678269004673,"results":"298","hashOfConfig":"250"},{"size":97,"mtime":1678269004673,"results":"299","hashOfConfig":"250"},{"size":304,"mtime":1678269004673,"results":"300","hashOfConfig":"250"},{"size":1873,"mtime":1678699060173,"results":"301","hashOfConfig":"250"},{"size":22842,"mtime":1678699060173,"results":"302","hashOfConfig":"250"},{"size":3141,"mtime":1678699060173,"results":"303","hashOfConfig":"250"},{"size":125,"mtime":1678699060173,"results":"304","hashOfConfig":"250"},{"size":6848,"mtime":1678699148573,"results":"305","hashOfConfig":"250"},{"size":4006,"mtime":1678699060173,"results":"306","hashOfConfig":"250"},{"size":842,"mtime":1678269004681,"results":"307","hashOfConfig":"250"},{"size":54,"mtime":1678699060173,"results":"308","hashOfConfig":"250"},{"size":6542,"mtime":1678699060173,"results":"309","hashOfConfig":"250"},{"size":17421,"mtime":1678699178764,"results":"310","hashOfConfig":"250"},{"size":2522,"mtime":1678699060173,"results":"311","hashOfConfig":"250"},{"size":8357,"mtime":1678269004681,"results":"312","hashOfConfig":"250"},{"size":16632,"mtime":1678699060173,"results":"313","hashOfConfig":"250"},{"size":22691,"mtime":1678699060177,"results":"314","hashOfConfig":"250"},{"size":80,"mtime":1678269004681,"results":"315","hashOfConfig":"250"},{"size":1226,"mtime":1678699060177,"results":"316","hashOfConfig":"250"},{"size":1974,"mtime":1678699060177,"results":"317","hashOfConfig":"250"},{"size":4314,"mtime":1678269004681,"results":"318","hashOfConfig":"250"},{"size":16717,"mtime":1678699060177,"results":"319","hashOfConfig":"250"},{"size":3220,"mtime":1678699060177,"results":"320","hashOfConfig":"250"},{"size":1522,"mtime":1678699060177,"results":"321","hashOfConfig":"250"},{"size":15140,"mtime":1678699060177,"results":"322","hashOfConfig":"250"},{"size":59,"mtime":1678699060177,"results":"323","hashOfConfig":"250"},{"size":275,"mtime":1678699060177,"results":"324","hashOfConfig":"250"},{"size":2733,"mtime":1678699060177,"results":"325","hashOfConfig":"250"},{"size":660,"mtime":1678269004681,"results":"326","hashOfConfig":"250"},{"size":8920,"mtime":1678699060177,"results":"327","hashOfConfig":"250"},{"size":358,"mtime":1678699060177,"results":"328","hashOfConfig":"250"},{"size":1214,"mtime":1678699060177,"results":"329","hashOfConfig":"250"},{"size":37,"mtime":1678699060177,"results":"330","hashOfConfig":"250"},{"size":9496,"mtime":1678699060177,"results":"331","hashOfConfig":"250"},{"size":280,"mtime":1678269004685,"results":"332","hashOfConfig":"250"},{"filePath":"333","messages":"334","suppressedMessages":"335","errorCount":25,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},"vl0kru",{"filePath":"336","messages":"337","suppressedMessages":"338","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"339","messages":"340","suppressedMessages":"341","errorCount":4,"fatalErrorCount":0,"warningCount":15,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"342","messages":"343","suppressedMessages":"344","errorCount":2,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"345","messages":"346","suppressedMessages":"347","errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"348","messages":"349","suppressedMessages":"350","errorCount":0,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"351","messages":"352","suppressedMessages":"353","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"354","messages":"355","suppressedMessages":"356","errorCount":3,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"357","messages":"358","suppressedMessages":"359","errorCount":1,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"360","messages":"361","suppressedMessages":"362","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"363","messages":"364","suppressedMessages":"365","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"366","messages":"367","suppressedMessages":"368","errorCount":7,"fatalErrorCount":0,"warningCount":17,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"369","messages":"370","suppressedMessages":"371","errorCount":1,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"372","messages":"373","suppressedMessages":"374","errorCount":8,"fatalErrorCount":0,"warningCount":11,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"375","messages":"376","suppressedMessages":"377","errorCount":4,"fatalErrorCount":0,"warningCount":12,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"378","messages":"379","suppressedMessages":"380","errorCount":3,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"381","messages":"382","suppressedMessages":"383","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"384","messages":"385","suppressedMessages":"386","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"387","messages":"388","suppressedMessages":"389","errorCount":2,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"390","messages":"391","suppressedMessages":"392","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"393","messages":"394","suppressedMessages":"395","errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"396","messages":"397","suppressedMessages":"398","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"399","messages":"400","suppressedMessages":"401","errorCount":2,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"402","messages":"403","suppressedMessages":"404","errorCount":10,"fatalErrorCount":0,"warningCount":16,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"405","messages":"406","suppressedMessages":"407","errorCount":1,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"408","messages":"409","suppressedMessages":"410","errorCount":1,"fatalErrorCount":0,"warningCount":12,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"411","messages":"412","suppressedMessages":"413","errorCount":3,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"414","messages":"415","suppressedMessages":"416","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"417","messages":"418","suppressedMessages":"419","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"420","messages":"421","suppressedMessages":"422","errorCount":11,"fatalErrorCount":0,"warningCount":13,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"423","messages":"424","suppressedMessages":"425","errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"426","messages":"427","suppressedMessages":"428","errorCount":58,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":1,"fixableWarningCount":0,"source":null},{"filePath":"429","messages":"430","suppressedMessages":"431","errorCount":5,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"432","messages":"433","suppressedMessages":"434","errorCount":1,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"435","messages":"436","suppressedMessages":"437","errorCount":1,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"438","messages":"439","suppressedMessages":"440","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"441","messages":"442","suppressedMessages":"443","errorCount":2,"fatalErrorCount":0,"warningCount":12,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"444","messages":"445","suppressedMessages":"446","errorCount":12,"fatalErrorCount":0,"warningCount":15,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"447","messages":"448","suppressedMessages":"449","errorCount":8,"fatalErrorCount":0,"warningCount":13,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"450","messages":"451","suppressedMessages":"452","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"453","messages":"454","suppressedMessages":"455","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"456","messages":"457","suppressedMessages":"458","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"459","messages":"460","suppressedMessages":"461","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"462","messages":"463","suppressedMessages":"464","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"465","messages":"466","suppressedMessages":"467","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"468","messages":"469","suppressedMessages":"470","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"471","messages":"472","suppressedMessages":"473","errorCount":1,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"474","messages":"475","suppressedMessages":"476","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"477","messages":"478","suppressedMessages":"479","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"480","messages":"481","suppressedMessages":"482","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"483","messages":"484","suppressedMessages":"485","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"486","messages":"487","suppressedMessages":"488","errorCount":2,"fatalErrorCount":0,"warningCount":13,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"489","messages":"490","suppressedMessages":"491","errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"492","messages":"493","suppressedMessages":"494","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"495","messages":"496","suppressedMessages":"497","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"498","messages":"499","suppressedMessages":"500","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"501","messages":"502","suppressedMessages":"503","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"504","messages":"505","suppressedMessages":"506","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"507","messages":"508","suppressedMessages":"509","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"510","messages":"511","suppressedMessages":"512","errorCount":1,"fatalErrorCount":0,"warningCount":10,"fixableErrorCount":1,"fixableWarningCount":0,"source":null},{"filePath":"513","messages":"514","suppressedMessages":"515","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"516","messages":"517","suppressedMessages":"518","errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"519","messages":"520","suppressedMessages":"521","errorCount":7,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"522","messages":"523","suppressedMessages":"524","errorCount":17,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"525","messages":"526","suppressedMessages":"527","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"528","messages":"529","suppressedMessages":"530","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"531","messages":"532","suppressedMessages":"533","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"534","messages":"535","suppressedMessages":"536","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"537","messages":"538","suppressedMessages":"539","errorCount":3,"fatalErrorCount":0,"warningCount":16,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"540","messages":"541","suppressedMessages":"542","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"543","messages":"544","suppressedMessages":"545","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"546","messages":"547","suppressedMessages":"548","errorCount":3,"fatalErrorCount":0,"warningCount":10,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"549","messages":"550","suppressedMessages":"551","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"552","messages":"553","suppressedMessages":"554","errorCount":60,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"555","messages":"556","suppressedMessages":"557","errorCount":1,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"558","messages":"559","suppressedMessages":"560","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"561","messages":"562","suppressedMessages":"563","errorCount":1,"fatalErrorCount":0,"warningCount":11,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"564","messages":"565","suppressedMessages":"566","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"567","messages":"568","suppressedMessages":"569","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"570","messages":"571","suppressedMessages":"572","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"573","messages":"574","suppressedMessages":"575","errorCount":0,"fatalErrorCount":0,"warningCount":7,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"576","messages":"577","suppressedMessages":"578","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"579","messages":"580","suppressedMessages":"581","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},"5nmhld",{"filePath":"582","messages":"583","suppressedMessages":"584","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"585","messages":"586","suppressedMessages":"587","errorCount":0,"fatalErrorCount":0,"warningCount":15,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"588","messages":"589","suppressedMessages":"590","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"591","messages":"592","suppressedMessages":"593","errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"594","messages":"595","suppressedMessages":"596","errorCount":0,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"597","messages":"598","suppressedMessages":"599","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"600","messages":"601","suppressedMessages":"602","errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"603","messages":"604","suppressedMessages":"605","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"606","messages":"607","suppressedMessages":"608","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"609","messages":"610","suppressedMessages":"611","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"612","messages":"613","suppressedMessages":"614","errorCount":0,"fatalErrorCount":0,"warningCount":17,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"615","messages":"616","suppressedMessages":"617","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"618","messages":"619","suppressedMessages":"620","errorCount":0,"fatalErrorCount":0,"warningCount":11,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"621","messages":"622","suppressedMessages":"623","errorCount":0,"fatalErrorCount":0,"warningCount":12,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"624","messages":"625","suppressedMessages":"626","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"627","messages":"628","suppressedMessages":"629","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"630","messages":"631","suppressedMessages":"632","errorCount":0,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"633","messages":"634","suppressedMessages":"635","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"636","messages":"637","suppressedMessages":"638","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"639","messages":"640","suppressedMessages":"641","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"642","messages":"643","suppressedMessages":"644","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"645","messages":"646","suppressedMessages":"647","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"648","messages":"649","suppressedMessages":"650","errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"651","messages":"652","suppressedMessages":"653","errorCount":0,"fatalErrorCount":0,"warningCount":16,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"654","messages":"655","suppressedMessages":"656","errorCount":0,"fatalErrorCount":0,"warningCount":7,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"657","messages":"658","suppressedMessages":"659","errorCount":0,"fatalErrorCount":0,"warningCount":12,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"660","messages":"661","suppressedMessages":"662","errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"663","messages":"664","suppressedMessages":"665","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"666","messages":"667","suppressedMessages":"668","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"669","messages":"670","suppressedMessages":"671","errorCount":0,"fatalErrorCount":0,"warningCount":13,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"672","messages":"673","suppressedMessages":"674","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"675","messages":"676","suppressedMessages":"677","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"678","messages":"679","suppressedMessages":"680","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"681","messages":"682","suppressedMessages":"683","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"684","messages":"685","suppressedMessages":"686","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"687","messages":"688","suppressedMessages":"689","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"690","messages":"691","suppressedMessages":"692","errorCount":0,"fatalErrorCount":0,"warningCount":12,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"693","messages":"694","suppressedMessages":"695","errorCount":0,"fatalErrorCount":0,"warningCount":15,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"696","messages":"697","suppressedMessages":"698","errorCount":0,"fatalErrorCount":0,"warningCount":13,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"699","messages":"700","suppressedMessages":"701","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"702","messages":"703","suppressedMessages":"704","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"705","messages":"706","suppressedMessages":"707","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"708","messages":"709","suppressedMessages":"710","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"711","messages":"712","suppressedMessages":"713","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"714","messages":"715","suppressedMessages":"716","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"717","messages":"718","suppressedMessages":"719","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"720","messages":"721","suppressedMessages":"722","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"723","messages":"724","suppressedMessages":"725","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"726","messages":"727","suppressedMessages":"728","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"729","messages":"730","suppressedMessages":"731","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"732","messages":"733","suppressedMessages":"734","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"735","messages":"736","suppressedMessages":"737","errorCount":0,"fatalErrorCount":0,"warningCount":13,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"738","messages":"739","suppressedMessages":"740","errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"741","messages":"742","suppressedMessages":"743","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"744","messages":"745","suppressedMessages":"746","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"747","messages":"748","suppressedMessages":"749","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"750","messages":"751","suppressedMessages":"752","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"753","messages":"754","suppressedMessages":"755","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"756","messages":"757","suppressedMessages":"758","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"759","messages":"760","suppressedMessages":"761","errorCount":0,"fatalErrorCount":0,"warningCount":10,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"762","messages":"763","suppressedMessages":"764","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"765","messages":"766","suppressedMessages":"767","errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"768","messages":"769","suppressedMessages":"770","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"771","messages":"772","suppressedMessages":"773","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"774","messages":"775","suppressedMessages":"776","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"777","messages":"778","suppressedMessages":"779","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"780","messages":"781","suppressedMessages":"782","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"783","messages":"784","suppressedMessages":"785","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"786","messages":"787","suppressedMessages":"788","errorCount":0,"fatalErrorCount":0,"warningCount":16,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"789","messages":"790","suppressedMessages":"791","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"792","messages":"793","suppressedMessages":"794","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"795","messages":"796","suppressedMessages":"797","errorCount":0,"fatalErrorCount":0,"warningCount":10,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"798","messages":"799","suppressedMessages":"800","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"801","messages":"802","suppressedMessages":"803","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"804","messages":"805","suppressedMessages":"806","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"807","messages":"808","suppressedMessages":"809","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"810","messages":"811","suppressedMessages":"812","errorCount":0,"fatalErrorCount":0,"warningCount":11,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"813","messages":"814","suppressedMessages":"815","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"816","messages":"817","suppressedMessages":"818","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"819","messages":"820","suppressedMessages":"821","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"822","messages":"823","suppressedMessages":"824","errorCount":0,"fatalErrorCount":0,"warningCount":7,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"825","messages":"826","suppressedMessages":"827","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/home/oltion/workspaces/coral/coral/coral/src/Cohort.ts",["828","829","830","831","832","833","834","835","836","837","838","839","840","841","842","843","844","845","846","847","848","849","850","851","852","853","854"],[],"/home/oltion/workspaces/coral/coral/coral/src/CohortContext.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/CohortRepresentations.ts",["855","856","857","858","859","860","861","862","863","864","865","866","867","868","869","870","871","872","873"],[],"/home/oltion/workspaces/coral/coral/coral/src/OnboardingManager.ts",["874","875","876"],[],"/home/oltion/workspaces/coral/coral/coral/src/Overview/CohortOverview.ts",["877","878","879","880","881","882"],[],"/home/oltion/workspaces/coral/coral/coral/src/Overview/OverviewLayout.ts",["883","884","885","886","887"],[],"/home/oltion/workspaces/coral/coral/coral/src/Overview/index.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/Provenance/CohortEV.ts",["888","889","890","891","892","893","894","895","896"],[],"/home/oltion/workspaces/coral/coral/coral/src/Provenance/General.ts",["897","898"],[],"/home/oltion/workspaces/coral/coral/coral/src/TaskRepresentations.ts",["899","900"],[],"/home/oltion/workspaces/coral/coral/coral/src/Tasks.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/SearchBar.ts",["901","902","903","904","905","906","907","908","909","910","911","912","913","914","915","916","917","918","919","920","921","922","923","924"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/SearchColumn.ts",["925","926","927","928","929"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/Taskview.ts",["930","931","932","933","934","935","936","937","938","939","940","941","942","943","944","945","946","947","948"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/columns/AColumn.ts",["949","950","951","952","953","954","955","956","957","958","959","960","961","962","963","964"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/columns/AttributeColumn.ts",["965","966","967","968","969","970","971","972"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/columns/CohortColumn.ts",["973"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/columns/NumberColumn.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/columns/PrevalenceColumn.ts",["974","975","976"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/columns/index.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/index.ts",["977","978"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/interfaces.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/tasks/ATask.ts",["979","980","981","982","983","984","985","986"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/tasks/Compare.ts",["987","988","989","990","991","992","993","994","995","996","997","998","999","1000","1001","1002","1003","1004","1005","1006","1007","1008","1009","1010","1011","1012"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/tasks/Details.ts",["1013","1014","1015","1016","1017","1018","1019"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/tasks/Filter.ts",["1020","1021","1022","1023","1024","1025","1026","1027","1028","1029","1030","1031","1032"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/tasks/Prevalence.ts",["1033","1034","1035","1036","1037","1038","1039","1040","1041"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/tasks/TaskList.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/tasks/index.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/AVegaVisualization.ts",["1042","1043","1044","1045","1046","1047","1048","1049","1050","1051","1052","1053","1054","1055","1056","1057","1058","1059","1060","1061","1062","1063","1064","1065"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/AreaChart.ts",["1066"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/DensityPlot.ts",["1067","1068","1069","1070","1071","1072","1073","1074","1075","1076","1077","1078","1079","1080","1081","1082","1083","1084","1085","1086","1087","1088","1089","1090","1091","1092","1093","1094","1095","1096","1097","1098","1099","1100","1101","1102","1103","1104","1105","1106","1107","1108","1109","1110","1111","1112","1113","1114","1115","1116","1117","1118","1119","1120","1121","1122","1123","1124"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/GroupedBoxplot.ts",["1125","1126","1127","1128","1129","1130","1131","1132","1133"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/GroupedHistogram.ts",["1134","1135"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/Histogram.ts",["1136","1137"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/IVisualization.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/KaplanMeierPlot.ts",["1138","1139","1140","1141","1142","1143","1144","1145","1146","1147","1148","1149","1150","1151"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/MultiAttributeVisualization.ts",["1152","1153","1154","1155","1156","1157","1158","1159","1160","1161","1162","1163","1164","1165","1166","1167","1168","1169","1170","1171","1172","1173","1174","1175","1176","1177","1178"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/Scatterplot.ts",["1179","1180","1181","1182","1183","1184","1185","1186","1187","1188","1189","1190","1191","1192","1193","1194","1195","1196","1197","1198","1199"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/config/ConfidenceConfig.ts",["1200"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/config/CountCounfig.ts",["1201"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/config/GroupConfig.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/config/ScaleConfig.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/config/SortConfig.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/config/VisConfig.ts",["1202"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/constants.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/dimreduce/OneHotEncoder.ts",["1203","1204"],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/dimreduce/OneHotEncoder.worker.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/dimreduce/tsne.worker.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/Taskview/visualizations/index.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/app/Coral.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/app/CoralApp.ts",["1205","1206","1207","1208","1209","1210","1211","1212","1213","1214","1215","1216","1217","1218","1219"],[],"/home/oltion/workspaces/coral/coral/coral/src/app/CoralSelectionListener.ts",["1220","1221","1222","1223","1224","1225"],[],"/home/oltion/workspaces/coral/coral/coral/src/app/index.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/app/interfaces.ts",["1226","1227","1228","1229"],[],"/home/oltion/workspaces/coral/coral/coral/src/base/events.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/base/extensions.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/base/index.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/base/interfaces.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/base/rest.ts",["1230","1231","1232","1233","1234","1235","1236","1237","1238","1239","1240"],[],"/home/oltion/workspaces/coral/coral/coral/src/cohortview.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/common/GeneUtils.ts",["1241","1242","1243","1244","1245","1246"],[],"/home/oltion/workspaces/coral/coral/coral/src/common/config.ts",["1247","1248","1249","1250","1251","1252","1253","1254","1255","1256"],[],"/home/oltion/workspaces/coral/coral/coral/src/common/forms.ts",["1257","1258","1259","1260","1261","1262","1263","1264","1265","1266","1267","1268","1269","1270","1271","1272","1273","1274","1275","1276","1277"],[],"/home/oltion/workspaces/coral/coral/coral/src/common/index.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/config/colors.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/config/entities.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/config/onboarding.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/data/Attribute.ts",["1278","1279","1280","1281","1282","1283","1284","1285","1286","1287","1288","1289","1290","1291","1292","1293","1294","1295","1296"],[],"/home/oltion/workspaces/coral/coral/coral/src/data/IAttribute.ts",["1297","1298"],[],"/home/oltion/workspaces/coral/coral/coral/src/data/ISpecialAttribute.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/data/SpecialAttribute.ts",["1299","1300","1301","1302","1303","1304","1305","1306","1307","1308","1309","1310","1311"],[],"/home/oltion/workspaces/coral/coral/coral/src/data/index.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/index.ts",["1312","1313","1314","1315","1316","1317","1318","1319","1320","1321","1322","1323","1324","1325","1326","1327","1328","1329","1330","1331","1332","1333","1334","1335","1336","1337","1338","1339","1340","1341","1342","1343","1344","1345","1346","1347","1348","1349","1350","1351","1352","1353","1354","1355","1356","1357","1358","1359","1360","1361","1362","1363","1364","1365","1366","1367","1368","1369","1370","1371"],[],"/home/oltion/workspaces/coral/coral/coral/src/phovea.ts",["1372","1373","1374","1375","1376"],[],"/home/oltion/workspaces/coral/coral/coral/src/phovea_registry.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/util.ts",["1377","1378","1379","1380","1381","1382","1383","1384","1385","1386","1387","1388"],[],"/home/oltion/workspaces/coral/coral/coral/src/utils/RouterScrollToTop.tsx",[],[],"/home/oltion/workspaces/coral/coral/coral/src/utils/ScrollLinker.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/utils/index.ts",[],[],"/home/oltion/workspaces/coral/coral/coral/src/utils/labels.ts",["1389","1390","1391","1392","1393","1394","1395"],[],"/home/oltion/workspaces/coral/coral/coral/tests/app.test.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Cohort.ts",["1396","1397"],["1398","1399","1400","1401","1402","1403","1404","1405","1406","1407","1408","1409","1410","1411","1412","1413","1414","1415","1416","1417","1418","1419","1420","1421","1422"],"/home/oltion/workspaces/coral/latest/coral/coral/src/CohortContext.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/CohortRepresentations.ts",["1423","1424","1425","1426","1427","1428","1429","1430","1431","1432","1433","1434","1435","1436","1437"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/OnboardingManager.ts",["1438"],["1439"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Overview/CohortOverview.ts",["1440","1441","1442","1443","1444","1445"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Overview/OverviewLayout.ts",["1446","1447","1448","1449","1450"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Overview/index.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Provenance/CohortEV.ts",["1451","1452","1453","1454","1455","1456"],["1457","1458","1459"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Provenance/General.ts",["1460"],["1461"],"/home/oltion/workspaces/coral/latest/coral/coral/src/TaskRepresentations.ts",["1462","1463"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Tasks.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/SearchBar.ts",["1464","1465","1466","1467","1468","1469","1470","1471","1472","1473","1474","1475","1476","1477","1478","1479","1480"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/SearchColumn.ts",["1481","1482","1483","1484"],["1485"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/Taskview.ts",["1486","1487","1488","1489","1490","1491","1492","1493","1494","1495","1496"],["1497","1498","1499"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/columns/AColumn.ts",["1500","1501","1502","1503","1504","1505","1506","1507","1508","1509","1510","1511"],["1512","1513"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/columns/AttributeColumn.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/columns/CohortColumn.ts",["1514"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/columns/Histogram.ts",["1515","1516","1517","1518","1519"],["1520"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/columns/NumberColumn.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/columns/PrevalenceColumn.ts",["1521"],["1522"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/columns/index.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/index.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/interfaces.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/tasks/ATask.ts",["1523","1524","1525","1526","1527","1528"],["1529","1530"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/tasks/Compare.ts",["1531","1532","1533","1534","1535","1536","1537","1538","1539","1540","1541","1542","1543","1544","1545","1546"],["1547","1548","1549","1550","1551","1552","1553"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/tasks/Details.ts",["1554","1555","1556","1557","1558","1559","1560"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/tasks/Filter.ts",["1561","1562","1563","1564","1565","1566","1567","1568","1569","1570","1571","1572"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/tasks/Prevalence.ts",["1573","1574","1575","1576","1577","1578"],["1579","1580"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/tasks/TaskList.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/tasks/index.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/AVegaVisualization.ts",["1581","1582","1583","1584","1585","1586","1587","1588","1589","1590","1591","1592","1593"],["1594","1595","1596","1597","1598","1599","1600"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/AreaChart.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/DensityPlot.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/GroupedBoxplot.ts",["1601","1602","1603","1604"],["1605","1606"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/GroupedHistogram.ts",["1607"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/Histogram.ts",["1608"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/IVisualization.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/KaplanMeierPlot.ts",["1609","1610","1611","1612","1613","1614","1615","1616","1617","1618","1619","1620"],["1621"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/MultiAttributeVisualization.ts",["1622","1623","1624","1625","1626","1627","1628","1629","1630","1631","1632","1633","1634","1635","1636"],["1637","1638","1639","1640","1641","1642","1643","1644"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/Scatterplot.ts",["1645","1646","1647","1648","1649","1650","1651","1652","1653","1654","1655","1656","1657"],["1658","1659","1660","1661","1662"],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/config/ConfidenceConfig.ts",["1663"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/config/CountCounfig.ts",["1664"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/config/GroupConfig.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/config/ScaleConfig.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/config/SortConfig.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/config/VisConfig.ts",["1665"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/constants.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/dimreduce/OneHotEncoder.ts",["1666"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/dimreduce/OneHotEncoder.worker.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/dimreduce/tsne.worker.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/Taskview/visualizations/index.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/app/Coral.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/app/CoralApp.ts",["1667","1668","1669","1670","1671","1672","1673","1674","1675","1676","1677","1678","1679"],["1680"],"/home/oltion/workspaces/coral/latest/coral/coral/src/app/CoralSelectionListener.ts",["1681","1682","1683","1684","1685","1686"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/app/index.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/app/interfaces.ts",["1687","1688","1689","1690"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/base/events.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/base/extensions.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/base/index.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/base/interfaces.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/base/rest.ts",["1691","1692","1693","1694","1695","1696","1697","1698","1699","1700"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/cohortview.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/common/GeneUtils.ts",["1701","1702","1703","1704","1705","1706"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/common/config.ts",["1707","1708","1709"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/common/forms.ts",["1710","1711","1712","1713"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/common/index.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/config/colors.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/config/entities.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/config/onboarding.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/data/Attribute.ts",["1714","1715","1716","1717","1718","1719","1720","1721","1722","1723","1724","1725","1726","1727","1728","1729"],["1730"],"/home/oltion/workspaces/coral/latest/coral/coral/src/data/IAttribute.ts",["1731","1732"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/data/ISpecialAttribute.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/data/SpecialAttribute.ts",["1733","1734","1735","1736","1737","1738","1739","1740","1741","1742"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/data/index.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/index.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/phovea.ts",["1743","1744","1745"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/phovea_registry.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/util.ts",["1746","1747","1748","1749","1750","1751","1752","1753","1754","1755","1756"],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/utils/RouterScrollToTop.tsx",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/utils/ScrollLinker.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/utils/index.ts",[],[],"/home/oltion/workspaces/coral/latest/coral/coral/src/utils/labels.ts",["1757","1758","1759","1760","1761","1762","1763"],[],"/home/oltion/workspaces/coral/latest/coral/coral/tests/app.test.ts",[],[],{"ruleId":"1764","severity":2,"message":"1765","line":95,"column":11,"nodeType":"1766","messageId":"1767","endLine":95,"endColumn":29},{"ruleId":"1764","severity":2,"message":"1768","line":103,"column":22,"nodeType":"1766","messageId":"1767","endLine":103,"endColumn":45},{"ruleId":"1764","severity":2,"message":"1769","line":106,"column":19,"nodeType":"1766","messageId":"1767","endLine":106,"endColumn":25},{"ruleId":"1764","severity":2,"message":"1765","line":143,"column":11,"nodeType":"1766","messageId":"1767","endLine":143,"endColumn":29},{"ruleId":"1764","severity":2,"message":"1768","line":149,"column":22,"nodeType":"1766","messageId":"1767","endLine":149,"endColumn":45},{"ruleId":"1764","severity":2,"message":"1769","line":154,"column":19,"nodeType":"1766","messageId":"1767","endLine":154,"endColumn":25},{"ruleId":"1764","severity":2,"message":"1765","line":181,"column":11,"nodeType":"1766","messageId":"1767","endLine":181,"endColumn":29},{"ruleId":"1764","severity":2,"message":"1768","line":187,"column":22,"nodeType":"1766","messageId":"1767","endLine":187,"endColumn":45},{"ruleId":"1764","severity":2,"message":"1769","line":192,"column":19,"nodeType":"1766","messageId":"1767","endLine":192,"endColumn":25},{"ruleId":"1764","severity":2,"message":"1765","line":218,"column":11,"nodeType":"1766","messageId":"1767","endLine":218,"endColumn":29},{"ruleId":"1764","severity":2,"message":"1768","line":223,"column":22,"nodeType":"1766","messageId":"1767","endLine":223,"endColumn":45},{"ruleId":"1764","severity":2,"message":"1769","line":228,"column":19,"nodeType":"1766","messageId":"1767","endLine":228,"endColumn":25},{"ruleId":"1764","severity":2,"message":"1765","line":256,"column":11,"nodeType":"1766","messageId":"1767","endLine":256,"endColumn":29},{"ruleId":"1764","severity":2,"message":"1768","line":263,"column":22,"nodeType":"1766","messageId":"1767","endLine":263,"endColumn":45},{"ruleId":"1764","severity":2,"message":"1769","line":269,"column":19,"nodeType":"1766","messageId":"1767","endLine":269,"endColumn":25},{"ruleId":"1764","severity":2,"message":"1765","line":298,"column":11,"nodeType":"1766","messageId":"1767","endLine":298,"endColumn":29},{"ruleId":"1764","severity":2,"message":"1768","line":306,"column":22,"nodeType":"1766","messageId":"1767","endLine":306,"endColumn":45},{"ruleId":"1764","severity":2,"message":"1769","line":312,"column":19,"nodeType":"1766","messageId":"1767","endLine":312,"endColumn":25},{"ruleId":"1764","severity":2,"message":"1765","line":341,"column":11,"nodeType":"1766","messageId":"1767","endLine":341,"endColumn":29},{"ruleId":"1764","severity":2,"message":"1768","line":349,"column":22,"nodeType":"1766","messageId":"1767","endLine":349,"endColumn":45},{"ruleId":"1764","severity":2,"message":"1769","line":355,"column":19,"nodeType":"1766","messageId":"1767","endLine":355,"endColumn":25},{"ruleId":"1764","severity":2,"message":"1765","line":381,"column":11,"nodeType":"1766","messageId":"1767","endLine":381,"endColumn":29},{"ruleId":"1764","severity":2,"message":"1768","line":386,"column":22,"nodeType":"1766","messageId":"1767","endLine":386,"endColumn":45},{"ruleId":"1764","severity":2,"message":"1769","line":392,"column":19,"nodeType":"1766","messageId":"1767","endLine":392,"endColumn":25},{"ruleId":"1764","severity":2,"message":"1769","line":468,"column":19,"nodeType":"1766","messageId":"1767","endLine":468,"endColumn":25},{"ruleId":"1770","severity":1,"message":"1771","line":469,"column":9,"nodeType":"1766","messageId":"1772","endLine":469,"endColumn":13},{"ruleId":"1773","severity":1,"message":"1774","line":871,"column":40,"nodeType":"1775","messageId":"1776","endLine":871,"endColumn":43,"suggestions":"1777"},{"ruleId":"1770","severity":1,"message":"1778","line":3,"column":10,"nodeType":"1766","messageId":"1772","endLine":3,"endColumn":27},{"ruleId":"1773","severity":1,"message":"1774","line":28,"column":23,"nodeType":"1775","messageId":"1776","endLine":28,"endColumn":26,"suggestions":"1779"},{"ruleId":"1770","severity":1,"message":"1780","line":55,"column":19,"nodeType":"1766","messageId":"1772","endLine":55,"endColumn":33},{"ruleId":"1770","severity":1,"message":"1781","line":55,"column":35,"nodeType":"1766","messageId":"1772","endLine":55,"endColumn":48},{"ruleId":"1773","severity":1,"message":"1774","line":174,"column":35,"nodeType":"1775","messageId":"1776","endLine":174,"endColumn":38,"suggestions":"1782"},{"ruleId":"1773","severity":1,"message":"1774","line":195,"column":41,"nodeType":"1775","messageId":"1776","endLine":195,"endColumn":44,"suggestions":"1783"},{"ruleId":"1784","severity":1,"message":"1785","line":214,"column":7,"nodeType":"1786","messageId":"1787","endLine":214,"endColumn":16},{"ruleId":"1773","severity":1,"message":"1774","line":227,"column":53,"nodeType":"1775","messageId":"1776","endLine":227,"endColumn":56,"suggestions":"1788"},{"ruleId":"1773","severity":1,"message":"1774","line":234,"column":58,"nodeType":"1775","messageId":"1776","endLine":234,"endColumn":61,"suggestions":"1789"},{"ruleId":"1770","severity":1,"message":"1790","line":273,"column":38,"nodeType":"1766","messageId":"1772","endLine":273,"endColumn":43},{"ruleId":"1773","severity":1,"message":"1774","line":385,"column":111,"nodeType":"1775","messageId":"1776","endLine":385,"endColumn":114,"suggestions":"1791"},{"ruleId":"1773","severity":1,"message":"1774","line":405,"column":121,"nodeType":"1775","messageId":"1776","endLine":405,"endColumn":124,"suggestions":"1792"},{"ruleId":"1773","severity":1,"message":"1774","line":427,"column":52,"nodeType":"1775","messageId":"1776","endLine":427,"endColumn":55,"suggestions":"1793"},{"ruleId":"1773","severity":1,"message":"1774","line":445,"column":46,"nodeType":"1775","messageId":"1776","endLine":445,"endColumn":49,"suggestions":"1794"},{"ruleId":"1795","severity":2,"message":"1796","line":510,"column":18,"nodeType":"1766","messageId":"1797","endLine":510,"endColumn":19},{"ruleId":"1770","severity":1,"message":"1798","line":530,"column":9,"nodeType":"1766","messageId":"1772","endLine":530,"endColumn":18},{"ruleId":"1795","severity":2,"message":"1799","line":602,"column":20,"nodeType":"1766","messageId":"1797","endLine":602,"endColumn":31},{"ruleId":"1795","severity":2,"message":"1800","line":617,"column":17,"nodeType":"1766","messageId":"1797","endLine":617,"endColumn":24},{"ruleId":"1795","severity":2,"message":"1801","line":634,"column":17,"nodeType":"1766","messageId":"1797","endLine":634,"endColumn":26},{"ruleId":"1773","severity":1,"message":"1774","line":9,"column":32,"nodeType":"1775","messageId":"1776","endLine":9,"endColumn":35,"suggestions":"1802"},{"ruleId":"1795","severity":2,"message":"1803","line":20,"column":30,"nodeType":"1766","messageId":"1797","endLine":20,"endColumn":33},{"ruleId":"1764","severity":2,"message":"1804","line":29,"column":7,"nodeType":"1766","messageId":"1767","endLine":29,"endColumn":26},{"ruleId":"1773","severity":1,"message":"1774","line":55,"column":26,"nodeType":"1775","messageId":"1776","endLine":55,"endColumn":29,"suggestions":"1805"},{"ruleId":"1770","severity":1,"message":"1806","line":117,"column":34,"nodeType":"1766","messageId":"1772","endLine":117,"endColumn":36},{"ruleId":"1770","severity":1,"message":"1807","line":126,"column":32,"nodeType":"1766","messageId":"1772","endLine":126,"endColumn":60},{"ruleId":"1770","severity":1,"message":"1808","line":848,"column":17,"nodeType":"1766","messageId":"1772","endLine":848,"endColumn":26},{"ruleId":"1770","severity":1,"message":"1790","line":929,"column":49,"nodeType":"1766","messageId":"1772","endLine":929,"endColumn":54},{"ruleId":"1770","severity":1,"message":"1809","line":964,"column":11,"nodeType":"1766","messageId":"1772","endLine":964,"endColumn":21},{"ruleId":"1773","severity":1,"message":"1774","line":6,"column":26,"nodeType":"1775","messageId":"1776","endLine":6,"endColumn":29,"suggestions":"1810"},{"ruleId":"1773","severity":1,"message":"1774","line":23,"column":38,"nodeType":"1775","messageId":"1776","endLine":23,"endColumn":41,"suggestions":"1811"},{"ruleId":"1812","severity":1,"message":"1813","line":47,"column":5,"nodeType":"1766","messageId":"1814","endLine":47,"endColumn":14},{"ruleId":"1812","severity":1,"message":"1813","line":48,"column":5,"nodeType":"1766","messageId":"1814","endLine":48,"endColumn":14},{"ruleId":"1770","severity":1,"message":"1815","line":90,"column":13,"nodeType":"1766","messageId":"1772","endLine":90,"endColumn":23},{"ruleId":"1764","severity":2,"message":"1816","line":24,"column":5,"nodeType":"1766","messageId":"1767","endLine":24,"endColumn":26},{"ruleId":"1773","severity":1,"message":"1774","line":33,"column":64,"nodeType":"1775","messageId":"1776","endLine":33,"endColumn":67,"suggestions":"1817"},{"ruleId":"1773","severity":1,"message":"1774","line":33,"column":83,"nodeType":"1775","messageId":"1776","endLine":33,"endColumn":86,"suggestions":"1818"},{"ruleId":"1764","severity":2,"message":"1819","line":43,"column":5,"nodeType":"1766","messageId":"1767","endLine":43,"endColumn":18},{"ruleId":"1773","severity":1,"message":"1774","line":51,"column":35,"nodeType":"1775","messageId":"1776","endLine":51,"endColumn":38,"suggestions":"1820"},{"ruleId":"1812","severity":1,"message":"1821","line":65,"column":3,"nodeType":"1766","messageId":"1814","endLine":65,"endColumn":6},{"ruleId":"1764","severity":2,"message":"1822","line":81,"column":5,"nodeType":"1766","messageId":"1767","endLine":81,"endColumn":29},{"ruleId":"1773","severity":1,"message":"1774","line":90,"column":67,"nodeType":"1775","messageId":"1776","endLine":90,"endColumn":70,"suggestions":"1823"},{"ruleId":"1773","severity":1,"message":"1774","line":90,"column":86,"nodeType":"1775","messageId":"1776","endLine":90,"endColumn":89,"suggestions":"1824"},{"ruleId":"1764","severity":2,"message":"1825","line":19,"column":5,"nodeType":"1766","messageId":"1767","endLine":19,"endColumn":19},{"ruleId":"1773","severity":1,"message":"1774","line":28,"column":81,"nodeType":"1775","messageId":"1776","endLine":28,"endColumn":84,"suggestions":"1826"},{"ruleId":"1773","severity":1,"message":"1774","line":85,"column":31,"nodeType":"1775","messageId":"1776","endLine":85,"endColumn":34,"suggestions":"1827"},{"ruleId":"1773","severity":1,"message":"1774","line":106,"column":37,"nodeType":"1775","messageId":"1776","endLine":106,"endColumn":40,"suggestions":"1828"},{"ruleId":"1773","severity":1,"message":"1774","line":38,"column":30,"nodeType":"1775","messageId":"1776","endLine":38,"endColumn":33,"suggestions":"1829"},{"ruleId":"1773","severity":1,"message":"1774","line":51,"column":48,"nodeType":"1775","messageId":"1776","endLine":51,"endColumn":51,"suggestions":"1830"},{"ruleId":"1773","severity":1,"message":"1774","line":108,"column":19,"nodeType":"1775","messageId":"1776","endLine":108,"endColumn":22,"suggestions":"1831"},{"ruleId":"1770","severity":1,"message":"1832","line":211,"column":11,"nodeType":"1766","messageId":"1772","endLine":211,"endColumn":34},{"ruleId":"1773","severity":1,"message":"1774","line":254,"column":31,"nodeType":"1775","messageId":"1776","endLine":254,"endColumn":34,"suggestions":"1833"},{"ruleId":"1770","severity":1,"message":"1834","line":325,"column":16,"nodeType":"1766","messageId":"1772","endLine":325,"endColumn":17},{"ruleId":"1773","severity":1,"message":"1774","line":376,"column":39,"nodeType":"1775","messageId":"1776","endLine":376,"endColumn":42,"suggestions":"1835"},{"ruleId":"1773","severity":1,"message":"1774","line":388,"column":67,"nodeType":"1775","messageId":"1776","endLine":388,"endColumn":70,"suggestions":"1836"},{"ruleId":"1837","severity":2,"message":"1838","line":395,"column":5,"nodeType":"1839","messageId":"1840","endLine":419,"endColumn":6},{"ruleId":"1841","severity":2,"message":"1842","line":397,"column":9,"nodeType":"1843","messageId":"1844","endLine":397,"endColumn":82},{"ruleId":"1773","severity":1,"message":"1774","line":447,"column":48,"nodeType":"1775","messageId":"1776","endLine":447,"endColumn":51,"suggestions":"1845"},{"ruleId":"1770","severity":1,"message":"1846","line":466,"column":11,"nodeType":"1766","messageId":"1772","endLine":466,"endColumn":19},{"ruleId":"1770","severity":1,"message":"1847","line":776,"column":35,"nodeType":"1766","messageId":"1772","endLine":776,"endColumn":43},{"ruleId":"1848","severity":1,"message":"1849","line":882,"column":43,"nodeType":"1850","messageId":"1851","endLine":882,"endColumn":108},{"ruleId":"1812","severity":1,"message":"1852","line":882,"column":50,"nodeType":"1766","messageId":"1814","endLine":882,"endColumn":56},{"ruleId":"1848","severity":1,"message":"1849","line":883,"column":43,"nodeType":"1850","messageId":"1851","endLine":883,"endColumn":84},{"ruleId":"1812","severity":1,"message":"1852","line":883,"column":50,"nodeType":"1766","messageId":"1814","endLine":883,"endColumn":56},{"ruleId":"1795","severity":2,"message":"1853","line":923,"column":32,"nodeType":"1766","messageId":"1797","endLine":923,"endColumn":53},{"ruleId":"1795","severity":2,"message":"1853","line":926,"column":40,"nodeType":"1766","messageId":"1797","endLine":926,"endColumn":61},{"ruleId":"1795","severity":2,"message":"1853","line":929,"column":18,"nodeType":"1766","messageId":"1797","endLine":929,"endColumn":39},{"ruleId":"1795","severity":2,"message":"1853","line":930,"column":32,"nodeType":"1766","messageId":"1797","endLine":930,"endColumn":53},{"ruleId":"1773","severity":1,"message":"1774","line":933,"column":62,"nodeType":"1775","messageId":"1776","endLine":933,"endColumn":65,"suggestions":"1854"},{"ruleId":"1855","severity":2,"message":"1856","line":957,"column":73,"nodeType":"1857","messageId":"1858","endLine":957,"endColumn":74},{"ruleId":"1770","severity":1,"message":"1846","line":972,"column":13,"nodeType":"1766","messageId":"1772","endLine":972,"endColumn":21},{"ruleId":"1770","severity":1,"message":"1847","line":75,"column":89,"nodeType":"1766","messageId":"1772","endLine":75,"endColumn":90},{"ruleId":"1859","severity":2,"message":"1860","line":141,"column":13,"nodeType":"1766","messageId":"1861","endLine":141,"endColumn":17},{"ruleId":"1784","severity":1,"message":"1785","line":144,"column":22,"nodeType":"1786","messageId":"1787","endLine":144,"endColumn":31},{"ruleId":"1862","severity":1,"message":"1863","line":158,"column":13,"nodeType":"1864","messageId":"1865","endLine":158,"endColumn":26},{"ruleId":"1862","severity":1,"message":"1863","line":160,"column":13,"nodeType":"1864","messageId":"1865","endLine":160,"endColumn":26},{"ruleId":"1770","severity":1,"message":"1806","line":79,"column":66,"nodeType":"1766","messageId":"1772","endLine":79,"endColumn":68},{"ruleId":"1764","severity":2,"message":"1866","line":87,"column":22,"nodeType":"1766","messageId":"1767","endLine":87,"endColumn":35},{"ruleId":"1764","severity":2,"message":"1867","line":95,"column":23,"nodeType":"1766","messageId":"1767","endLine":95,"endColumn":37},{"ruleId":"1868","severity":2,"message":"1869","line":124,"column":9,"nodeType":"1870","messageId":"1871","endLine":124,"endColumn":75},{"ruleId":"1868","severity":2,"message":"1869","line":192,"column":24,"nodeType":"1870","messageId":"1871","endLine":192,"endColumn":38},{"ruleId":"1784","severity":1,"message":"1785","line":202,"column":24,"nodeType":"1786","messageId":"1787","endLine":202,"endColumn":33},{"ruleId":"1773","severity":1,"message":"1774","line":218,"column":63,"nodeType":"1775","messageId":"1776","endLine":218,"endColumn":66,"suggestions":"1872"},{"ruleId":"1773","severity":1,"message":"1774","line":221,"column":65,"nodeType":"1775","messageId":"1776","endLine":221,"endColumn":68,"suggestions":"1873"},{"ruleId":"1874","severity":2,"message":"1875","line":302,"column":94,"nodeType":"1850","messageId":"1876","endLine":302,"endColumn":150},{"ruleId":"1868","severity":2,"message":"1869","line":330,"column":25,"nodeType":"1870","messageId":"1871","endLine":330,"endColumn":55},{"ruleId":"1868","severity":2,"message":"1869","line":354,"column":9,"nodeType":"1870","messageId":"1871","endLine":354,"endColumn":36},{"ruleId":"1877","severity":2,"message":"1878","line":500,"column":31,"nodeType":"1850","messageId":"1879","endLine":500,"endColumn":33},{"ruleId":"1848","severity":1,"message":"1849","line":557,"column":57,"nodeType":"1850","messageId":"1851","endLine":557,"endColumn":90},{"ruleId":"1812","severity":1,"message":"1880","line":557,"column":67,"nodeType":"1766","messageId":"1814","endLine":557,"endColumn":70},{"ruleId":"1812","severity":1,"message":"1881","line":583,"column":11,"nodeType":"1766","messageId":"1814","endLine":583,"endColumn":15},{"ruleId":"1812","severity":1,"message":"1881","line":589,"column":15,"nodeType":"1766","messageId":"1814","endLine":589,"endColumn":19},{"ruleId":"1812","severity":1,"message":"1882","line":639,"column":7,"nodeType":"1766","messageId":"1814","endLine":639,"endColumn":9},{"ruleId":"1848","severity":1,"message":"1849","line":663,"column":45,"nodeType":"1850","messageId":"1851","endLine":663,"endColumn":96},{"ruleId":"1812","severity":1,"message":"1880","line":663,"column":56,"nodeType":"1766","messageId":"1814","endLine":663,"endColumn":59},{"ruleId":"1883","severity":2,"message":"1884","line":8,"column":10,"nodeType":"1766","endLine":8,"endColumn":18},{"ruleId":"1885","severity":2,"message":"1886","line":127,"column":11,"nodeType":"1766","messageId":"1887","endLine":127,"endColumn":22},{"ruleId":"1859","severity":2,"message":"1860","line":127,"column":11,"nodeType":"1766","messageId":"1861","endLine":127,"endColumn":22},{"ruleId":"1784","severity":1,"message":"1785","line":130,"column":25,"nodeType":"1786","messageId":"1787","endLine":130,"endColumn":34},{"ruleId":"1784","severity":1,"message":"1785","line":139,"column":13,"nodeType":"1786","messageId":"1787","endLine":139,"endColumn":22},{"ruleId":"1770","severity":1,"message":"1888","line":167,"column":58,"nodeType":"1766","messageId":"1772","endLine":167,"endColumn":71},{"ruleId":"1812","severity":1,"message":"1889","line":176,"column":7,"nodeType":"1766","messageId":"1814","endLine":176,"endColumn":11},{"ruleId":"1812","severity":1,"message":"1889","line":180,"column":7,"nodeType":"1766","messageId":"1814","endLine":180,"endColumn":11},{"ruleId":"1812","severity":1,"message":"1889","line":194,"column":5,"nodeType":"1766","messageId":"1814","endLine":194,"endColumn":9},{"ruleId":"1770","severity":1,"message":"1890","line":213,"column":24,"nodeType":"1766","messageId":"1772","endLine":213,"endColumn":44},{"ruleId":"1770","severity":1,"message":"1891","line":213,"column":46,"nodeType":"1766","messageId":"1772","endLine":213,"endColumn":58},{"ruleId":"1770","severity":1,"message":"1888","line":213,"column":60,"nodeType":"1766","messageId":"1772","endLine":213,"endColumn":73},{"ruleId":"1795","severity":2,"message":"1892","line":219,"column":43,"nodeType":"1766","messageId":"1797","endLine":219,"endColumn":61},{"ruleId":"1770","severity":1,"message":"1890","line":249,"column":24,"nodeType":"1766","messageId":"1772","endLine":249,"endColumn":44},{"ruleId":"1770","severity":1,"message":"1891","line":249,"column":46,"nodeType":"1766","messageId":"1772","endLine":249,"endColumn":58},{"ruleId":"1770","severity":1,"message":"1888","line":249,"column":60,"nodeType":"1766","messageId":"1772","endLine":249,"endColumn":73},{"ruleId":"1764","severity":2,"message":"1893","line":157,"column":22,"nodeType":"1766","messageId":"1767","endLine":157,"endColumn":31},{"ruleId":"1773","severity":1,"message":"1774","line":170,"column":13,"nodeType":"1775","messageId":"1776","endLine":170,"endColumn":16,"suggestions":"1894"},{"ruleId":"1859","severity":2,"message":"1860","line":187,"column":11,"nodeType":"1766","messageId":"1861","endLine":187,"endColumn":15},{"ruleId":"1895","severity":2,"message":"1896","line":260,"column":11,"nodeType":"1897","messageId":"1898","endLine":274,"endColumn":12},{"ruleId":"1770","severity":1,"message":"1899","line":299,"column":37,"nodeType":"1766","messageId":"1772","endLine":299,"endColumn":78},{"ruleId":"1812","severity":1,"message":"1900","line":301,"column":7,"nodeType":"1766","messageId":"1901","endLine":301,"endColumn":12},{"ruleId":"1773","severity":1,"message":"1774","line":336,"column":15,"nodeType":"1775","messageId":"1776","endLine":336,"endColumn":18,"suggestions":"1902"},{"ruleId":"1773","severity":1,"message":"1774","line":399,"column":15,"nodeType":"1775","messageId":"1776","endLine":399,"endColumn":18,"suggestions":"1903"},{"ruleId":"1812","severity":1,"message":"1889","line":35,"column":5,"nodeType":"1766","messageId":"1814","endLine":35,"endColumn":9},{"ruleId":"1764","severity":2,"message":"1904","line":15,"column":26,"nodeType":"1766","messageId":"1767","endLine":15,"endColumn":39},{"ruleId":"1859","severity":2,"message":"1860","line":38,"column":11,"nodeType":"1766","messageId":"1861","endLine":38,"endColumn":15},{"ruleId":"1770","severity":1,"message":"1905","line":50,"column":11,"nodeType":"1766","messageId":"1772","endLine":50,"endColumn":15},{"ruleId":"1906","severity":2,"message":"1907","line":6,"column":15,"nodeType":"1908","endLine":6,"endColumn":31},{"ruleId":"1906","severity":2,"message":"1909","line":8,"column":15,"nodeType":"1908","endLine":8,"endColumn":27},{"ruleId":"1773","severity":1,"message":"1774","line":25,"column":45,"nodeType":"1775","messageId":"1776","endLine":25,"endColumn":48,"suggestions":"1910"},{"ruleId":"1773","severity":1,"message":"1774","line":27,"column":47,"nodeType":"1775","messageId":"1776","endLine":27,"endColumn":50,"suggestions":"1911"},{"ruleId":"1773","severity":1,"message":"1774","line":29,"column":45,"nodeType":"1775","messageId":"1776","endLine":29,"endColumn":48,"suggestions":"1912"},{"ruleId":"1770","severity":1,"message":"1913","line":35,"column":65,"nodeType":"1766","messageId":"1772","endLine":35,"endColumn":89},{"ruleId":"1770","severity":1,"message":"1914","line":35,"column":91,"nodeType":"1766","messageId":"1772","endLine":35,"endColumn":109},{"ruleId":"1859","severity":2,"message":"1860","line":36,"column":11,"nodeType":"1766","messageId":"1861","endLine":36,"endColumn":15},{"ruleId":"1784","severity":1,"message":"1785","line":58,"column":20,"nodeType":"1786","messageId":"1787","endLine":58,"endColumn":29},{"ruleId":"1859","severity":2,"message":"1860","line":59,"column":15,"nodeType":"1766","messageId":"1861","endLine":59,"endColumn":25},{"ruleId":"1770","severity":1,"message":"1915","line":48,"column":11,"nodeType":"1766","messageId":"1772","endLine":48,"endColumn":25},{"ruleId":"1773","severity":1,"message":"1774","line":63,"column":50,"nodeType":"1775","messageId":"1776","endLine":63,"endColumn":53,"suggestions":"1916"},{"ruleId":"1859","severity":2,"message":"1860","line":85,"column":11,"nodeType":"1766","messageId":"1861","endLine":85,"endColumn":15},{"ruleId":"1795","severity":2,"message":"1917","line":86,"column":73,"nodeType":"1766","messageId":"1797","endLine":86,"endColumn":90},{"ruleId":"1784","severity":1,"message":"1785","line":117,"column":28,"nodeType":"1786","messageId":"1787","endLine":117,"endColumn":37},{"ruleId":"1784","severity":1,"message":"1785","line":141,"column":22,"nodeType":"1786","messageId":"1787","endLine":141,"endColumn":31},{"ruleId":"1784","severity":1,"message":"1785","line":144,"column":26,"nodeType":"1786","messageId":"1787","endLine":144,"endColumn":35},{"ruleId":"1784","severity":1,"message":"1785","line":147,"column":25,"nodeType":"1786","messageId":"1787","endLine":147,"endColumn":34},{"ruleId":"1784","severity":1,"message":"1785","line":150,"column":24,"nodeType":"1786","messageId":"1787","endLine":150,"endColumn":33},{"ruleId":"1764","severity":2,"message":"1918","line":181,"column":5,"nodeType":"1766","messageId":"1767","endLine":181,"endColumn":17},{"ruleId":"1868","severity":2,"message":"1869","line":224,"column":28,"nodeType":"1870","messageId":"1871","endLine":224,"endColumn":59},{"ruleId":"1868","severity":2,"message":"1869","line":234,"column":32,"nodeType":"1870","messageId":"1871","endLine":234,"endColumn":63},{"ruleId":"1770","severity":1,"message":"1919","line":245,"column":55,"nodeType":"1766","messageId":"1772","endLine":245,"endColumn":61},{"ruleId":"1764","severity":2,"message":"1920","line":301,"column":23,"nodeType":"1766","messageId":"1767","endLine":301,"endColumn":43},{"ruleId":"1764","severity":2,"message":"1921","line":320,"column":17,"nodeType":"1766","messageId":"1767","endLine":320,"endColumn":28},{"ruleId":"1784","severity":1,"message":"1785","line":367,"column":15,"nodeType":"1786","messageId":"1787","endLine":367,"endColumn":24},{"ruleId":"1922","severity":2,"message":"1923","line":387,"column":76,"nodeType":"1766","messageId":"1924","endLine":387,"endColumn":81},{"ruleId":"1784","severity":1,"message":"1785","line":418,"column":54,"nodeType":"1786","messageId":"1787","endLine":418,"endColumn":63},{"ruleId":"1770","severity":1,"message":"1834","line":418,"column":64,"nodeType":"1766","messageId":"1772","endLine":418,"endColumn":65},{"ruleId":"1773","severity":1,"message":"1774","line":517,"column":50,"nodeType":"1775","messageId":"1776","endLine":517,"endColumn":53,"suggestions":"1925"},{"ruleId":"1859","severity":2,"message":"1860","line":525,"column":11,"nodeType":"1766","messageId":"1861","endLine":525,"endColumn":15},{"ruleId":"1784","severity":1,"message":"1785","line":528,"column":36,"nodeType":"1786","messageId":"1787","endLine":528,"endColumn":45},{"ruleId":"1922","severity":2,"message":"1923","line":549,"column":73,"nodeType":"1766","messageId":"1924","endLine":549,"endColumn":78},{"ruleId":"1773","severity":1,"message":"1774","line":566,"column":64,"nodeType":"1775","messageId":"1776","endLine":566,"endColumn":67,"suggestions":"1926"},{"ruleId":"1773","severity":1,"message":"1774","line":583,"column":64,"nodeType":"1775","messageId":"1776","endLine":583,"endColumn":67,"suggestions":"1927"},{"ruleId":"1773","severity":1,"message":"1774","line":764,"column":15,"nodeType":"1775","messageId":"1776","endLine":764,"endColumn":18,"suggestions":"1928"},{"ruleId":"1929","severity":2,"message":"1930","line":69,"column":35,"nodeType":"1766","messageId":"1931","endLine":69,"endColumn":40},{"ruleId":"1770","severity":1,"message":"1932","line":82,"column":58,"nodeType":"1766","messageId":"1772","endLine":82,"endColumn":62},{"ruleId":"1770","severity":1,"message":"1933","line":82,"column":64,"nodeType":"1766","messageId":"1772","endLine":82,"endColumn":69},{"ruleId":"1773","severity":1,"message":"1774","line":90,"column":21,"nodeType":"1775","messageId":"1776","endLine":90,"endColumn":24,"suggestions":"1934"},{"ruleId":"1773","severity":1,"message":"1774","line":91,"column":33,"nodeType":"1775","messageId":"1776","endLine":91,"endColumn":36,"suggestions":"1935"},{"ruleId":"1773","severity":1,"message":"1774","line":142,"column":47,"nodeType":"1775","messageId":"1776","endLine":142,"endColumn":50,"suggestions":"1936"},{"ruleId":"1937","severity":1,"message":"1938","line":156,"column":53,"nodeType":"1939","messageId":"1940","endLine":156,"endColumn":65,"suggestions":"1941"},{"ruleId":"1773","severity":1,"message":"1774","line":26,"column":39,"nodeType":"1775","messageId":"1776","endLine":26,"endColumn":42,"suggestions":"1942"},{"ruleId":"1770","severity":1,"message":"1913","line":130,"column":26,"nodeType":"1766","messageId":"1772","endLine":130,"endColumn":50},{"ruleId":"1770","severity":1,"message":"1914","line":130,"column":52,"nodeType":"1766","messageId":"1772","endLine":130,"endColumn":70},{"ruleId":"1784","severity":1,"message":"1785","line":139,"column":62,"nodeType":"1786","messageId":"1787","endLine":139,"endColumn":71},{"ruleId":"1773","severity":1,"message":"1774","line":160,"column":47,"nodeType":"1775","messageId":"1776","endLine":160,"endColumn":50,"suggestions":"1943"},{"ruleId":"1773","severity":1,"message":"1774","line":160,"column":86,"nodeType":"1775","messageId":"1776","endLine":160,"endColumn":89,"suggestions":"1944"},{"ruleId":"1773","severity":1,"message":"1774","line":162,"column":32,"nodeType":"1775","messageId":"1776","endLine":162,"endColumn":35,"suggestions":"1945"},{"ruleId":"1773","severity":1,"message":"1774","line":164,"column":28,"nodeType":"1775","messageId":"1776","endLine":164,"endColumn":31,"suggestions":"1946"},{"ruleId":"1773","severity":1,"message":"1774","line":164,"column":67,"nodeType":"1775","messageId":"1776","endLine":164,"endColumn":70,"suggestions":"1947"},{"ruleId":"1773","severity":1,"message":"1774","line":166,"column":102,"nodeType":"1775","messageId":"1776","endLine":166,"endColumn":105,"suggestions":"1948"},{"ruleId":"1773","severity":1,"message":"1774","line":166,"column":129,"nodeType":"1775","messageId":"1776","endLine":166,"endColumn":132,"suggestions":"1949"},{"ruleId":"1950","severity":2,"message":"1951","line":167,"column":34,"nodeType":"1952","messageId":"1953","endLine":167,"endColumn":42},{"ruleId":"1773","severity":1,"message":"1774","line":188,"column":38,"nodeType":"1775","messageId":"1776","endLine":188,"endColumn":41,"suggestions":"1954"},{"ruleId":"1883","severity":2,"message":"1955","line":5,"column":10,"nodeType":"1766","endLine":5,"endColumn":23},{"ruleId":"1770","severity":1,"message":"1790","line":148,"column":47,"nodeType":"1766","messageId":"1772","endLine":148,"endColumn":52},{"ruleId":"1770","severity":1,"message":"1956","line":181,"column":45,"nodeType":"1766","messageId":"1772","endLine":181,"endColumn":63},{"ruleId":"1770","severity":1,"message":"1790","line":288,"column":46,"nodeType":"1766","messageId":"1772","endLine":288,"endColumn":51},{"ruleId":"1770","severity":1,"message":"1957","line":591,"column":11,"nodeType":"1766","messageId":"1772","endLine":591,"endColumn":18},{"ruleId":"1868","severity":2,"message":"1869","line":809,"column":25,"nodeType":"1870","messageId":"1871","endLine":809,"endColumn":82},{"ruleId":"1868","severity":2,"message":"1869","line":819,"column":27,"nodeType":"1870","messageId":"1871","endLine":819,"endColumn":132},{"ruleId":"1773","severity":1,"message":"1774","line":970,"column":40,"nodeType":"1775","messageId":"1776","endLine":970,"endColumn":43,"suggestions":"1958"},{"ruleId":"1773","severity":1,"message":"1774","line":1007,"column":39,"nodeType":"1775","messageId":"1776","endLine":1007,"endColumn":42,"suggestions":"1959"},{"ruleId":"1960","severity":2,"message":"1961","line":67,"column":42,"nodeType":"1766","messageId":"1962","endLine":67,"endColumn":48},{"ruleId":"1773","severity":1,"message":"1774","line":78,"column":26,"nodeType":"1775","messageId":"1776","endLine":78,"endColumn":29,"suggestions":"1963"},{"ruleId":"1770","severity":1,"message":"1964","line":229,"column":17,"nodeType":"1766","messageId":"1772","endLine":229,"endColumn":18},{"ruleId":"1812","severity":1,"message":"1965","line":417,"column":7,"nodeType":"1766","messageId":"1814","endLine":417,"endColumn":12},{"ruleId":"1895","severity":2,"message":"1896","line":477,"column":9,"nodeType":"1897","messageId":"1898","endLine":528,"endColumn":10},{"ruleId":"1770","severity":1,"message":"1966","line":567,"column":13,"nodeType":"1766","messageId":"1772","endLine":567,"endColumn":27},{"ruleId":"1859","severity":2,"message":"1860","line":675,"column":11,"nodeType":"1766","messageId":"1861","endLine":675,"endColumn":15},{"ruleId":"1784","severity":1,"message":"1785","line":678,"column":20,"nodeType":"1786","messageId":"1787","endLine":678,"endColumn":29},{"ruleId":"1859","severity":2,"message":"1860","line":679,"column":15,"nodeType":"1766","messageId":"1861","endLine":679,"endColumn":22},{"ruleId":"1784","severity":1,"message":"1785","line":685,"column":30,"nodeType":"1786","messageId":"1787","endLine":685,"endColumn":39},{"ruleId":"1859","severity":2,"message":"1860","line":686,"column":13,"nodeType":"1766","messageId":"1861","endLine":686,"endColumn":20},{"ruleId":"1784","severity":1,"message":"1785","line":691,"column":35,"nodeType":"1786","messageId":"1787","endLine":691,"endColumn":44},{"ruleId":"1859","severity":2,"message":"1860","line":692,"column":13,"nodeType":"1766","messageId":"1861","endLine":692,"endColumn":20},{"ruleId":"1784","severity":1,"message":"1785","line":696,"column":33,"nodeType":"1786","messageId":"1787","endLine":696,"endColumn":42},{"ruleId":"1859","severity":2,"message":"1860","line":747,"column":11,"nodeType":"1766","messageId":"1861","endLine":747,"endColumn":22},{"ruleId":"1784","severity":1,"message":"1785","line":750,"column":20,"nodeType":"1786","messageId":"1787","endLine":750,"endColumn":29},{"ruleId":"1770","severity":1,"message":"1790","line":807,"column":28,"nodeType":"1766","messageId":"1772","endLine":807,"endColumn":33},{"ruleId":"1922","severity":2,"message":"1923","line":828,"column":36,"nodeType":"1766","messageId":"1924","endLine":828,"endColumn":41},{"ruleId":"1922","severity":2,"message":"1923","line":832,"column":36,"nodeType":"1766","messageId":"1924","endLine":832,"endColumn":41},{"ruleId":"1859","severity":2,"message":"1860","line":865,"column":13,"nodeType":"1766","messageId":"1861","endLine":865,"endColumn":17},{"ruleId":"1784","severity":1,"message":"1785","line":866,"column":27,"nodeType":"1786","messageId":"1787","endLine":866,"endColumn":36},{"ruleId":"1859","severity":2,"message":"1860","line":867,"column":15,"nodeType":"1766","messageId":"1861","endLine":867,"endColumn":22},{"ruleId":"1770","severity":1,"message":"1967","line":876,"column":24,"nodeType":"1766","messageId":"1772","endLine":876,"endColumn":28},{"ruleId":"1770","severity":1,"message":"1968","line":876,"column":30,"nodeType":"1766","messageId":"1772","endLine":876,"endColumn":35},{"ruleId":"1960","severity":2,"message":"1961","line":12,"column":32,"nodeType":"1766","messageId":"1962","endLine":12,"endColumn":38},{"ruleId":"1969","severity":2,"message":"1970","line":9,"column":9,"nodeType":null,"messageId":"1971","endLine":9,"endColumn":20,"fix":"1972"},{"ruleId":"1960","severity":2,"message":"1961","line":18,"column":32,"nodeType":"1766","messageId":"1962","endLine":18,"endColumn":38},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":31,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":32,"suggestions":"1977"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":56,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":57,"suggestions":"1978"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":73,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":74,"suggestions":"1979"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":80,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":81,"suggestions":"1980"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":85,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":86,"suggestions":"1981"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":87,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":88,"suggestions":"1982"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":92,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":93,"suggestions":"1983"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":101,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":102,"suggestions":"1984"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":118,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":119,"suggestions":"1985"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":127,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":128,"suggestions":"1986"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":132,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":133,"suggestions":"1987"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":134,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":135,"suggestions":"1988"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":139,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":140,"suggestions":"1989"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":146,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":147,"suggestions":"1990"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":163,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":164,"suggestions":"1991"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":170,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":171,"suggestions":"1992"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":175,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":176,"suggestions":"1993"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":177,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":178,"suggestions":"1994"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":182,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":183,"suggestions":"1995"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":197,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":198,"suggestions":"1996"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":215,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":216,"suggestions":"1997"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":230,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":231,"suggestions":"1998"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":243,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":244,"suggestions":"1999"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":258,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":259,"suggestions":"2000"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":264,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":265,"suggestions":"2001"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":266,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":267,"suggestions":"2002"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":275,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":276,"suggestions":"2003"},{"ruleId":"1973","severity":2,"message":"1974","line":386,"column":290,"nodeType":"1975","messageId":"1976","endLine":386,"endColumn":291,"suggestions":"2004"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":30,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":31,"suggestions":"2005"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":57,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":58,"suggestions":"2006"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":76,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":77,"suggestions":"2007"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":83,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":84,"suggestions":"2008"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":88,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":89,"suggestions":"2009"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":90,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":91,"suggestions":"2010"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":97,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":98,"suggestions":"2011"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":110,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":111,"suggestions":"2012"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":129,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":130,"suggestions":"2013"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":138,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":139,"suggestions":"2014"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":143,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":144,"suggestions":"2015"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":145,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":146,"suggestions":"2016"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":152,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":153,"suggestions":"2017"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":163,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":164,"suggestions":"2018"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":182,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":183,"suggestions":"2019"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":189,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":190,"suggestions":"2020"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":194,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":195,"suggestions":"2021"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":196,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":197,"suggestions":"2022"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":203,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":204,"suggestions":"2023"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":222,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":223,"suggestions":"2024"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":242,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":243,"suggestions":"2025"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":257,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":258,"suggestions":"2026"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":270,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":271,"suggestions":"2027"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":285,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":286,"suggestions":"2028"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":291,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":292,"suggestions":"2029"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":293,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":294,"suggestions":"2030"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":302,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":303,"suggestions":"2031"},{"ruleId":"1973","severity":2,"message":"1974","line":390,"column":317,"nodeType":"1975","messageId":"1976","endLine":390,"endColumn":318,"suggestions":"2032"},{"ruleId":"1960","severity":2,"message":"1961","line":24,"column":32,"nodeType":"1766","messageId":"1962","endLine":24,"endColumn":38},{"ruleId":"1812","severity":1,"message":"2033","line":40,"column":7,"nodeType":"1766","messageId":"1814","endLine":40,"endColumn":11},{"ruleId":"1770","severity":1,"message":"2034","line":57,"column":57,"nodeType":"1766","messageId":"1772","endLine":57,"endColumn":61},{"ruleId":"1770","severity":1,"message":"1790","line":61,"column":28,"nodeType":"1766","messageId":"1772","endLine":61,"endColumn":33},{"ruleId":"1922","severity":2,"message":"1923","line":70,"column":36,"nodeType":"1766","messageId":"1924","endLine":70,"endColumn":41},{"ruleId":"1922","severity":2,"message":"1923","line":73,"column":36,"nodeType":"1766","messageId":"1924","endLine":73,"endColumn":41},{"ruleId":"1859","severity":2,"message":"1860","line":109,"column":15,"nodeType":"1766","messageId":"1861","endLine":109,"endColumn":19},{"ruleId":"1784","severity":1,"message":"1785","line":110,"column":29,"nodeType":"1786","messageId":"1787","endLine":110,"endColumn":38},{"ruleId":"1859","severity":2,"message":"1860","line":111,"column":17,"nodeType":"1766","messageId":"1861","endLine":111,"endColumn":24},{"ruleId":"1960","severity":2,"message":"1961","line":21,"column":32,"nodeType":"1766","messageId":"1962","endLine":21,"endColumn":38},{"ruleId":"1773","severity":1,"message":"1774","line":194,"column":26,"nodeType":"1775","messageId":"1776","endLine":194,"endColumn":29,"suggestions":"2035"},{"ruleId":"1883","severity":2,"message":"2036","line":3,"column":10,"nodeType":"1766","endLine":3,"endColumn":21},{"ruleId":"1773","severity":1,"message":"1774","line":129,"column":28,"nodeType":"1775","messageId":"1776","endLine":129,"endColumn":31,"suggestions":"2037"},{"ruleId":"1770","severity":1,"message":"2038","line":3,"column":28,"nodeType":"1766","messageId":"1772","endLine":3,"endColumn":32},{"ruleId":"1960","severity":2,"message":"1961","line":27,"column":32,"nodeType":"1766","messageId":"1962","endLine":27,"endColumn":38},{"ruleId":"1929","severity":2,"message":"1930","line":59,"column":35,"nodeType":"1766","messageId":"1931","endLine":59,"endColumn":40},{"ruleId":"1770","severity":1,"message":"1964","line":64,"column":52,"nodeType":"1766","messageId":"1772","endLine":64,"endColumn":53},{"ruleId":"1812","severity":1,"message":"2039","line":81,"column":5,"nodeType":"1766","messageId":"1901","endLine":81,"endColumn":9},{"ruleId":"1773","severity":1,"message":"1774","line":485,"column":18,"nodeType":"1775","messageId":"1776","endLine":485,"endColumn":21,"suggestions":"2040"},{"ruleId":"1773","severity":1,"message":"1774","line":809,"column":35,"nodeType":"1775","messageId":"1776","endLine":809,"endColumn":38,"suggestions":"2041"},{"ruleId":"1773","severity":1,"message":"1774","line":809,"column":88,"nodeType":"1775","messageId":"1776","endLine":809,"endColumn":91,"suggestions":"2042"},{"ruleId":"1773","severity":1,"message":"1774","line":811,"column":21,"nodeType":"1775","messageId":"1776","endLine":811,"endColumn":24,"suggestions":"2043"},{"ruleId":"1773","severity":1,"message":"1774","line":816,"column":46,"nodeType":"1775","messageId":"1776","endLine":816,"endColumn":49,"suggestions":"2044"},{"ruleId":"1773","severity":1,"message":"1774","line":828,"column":38,"nodeType":"1775","messageId":"1776","endLine":828,"endColumn":41,"suggestions":"2045"},{"ruleId":"1773","severity":1,"message":"1774","line":828,"column":92,"nodeType":"1775","messageId":"1776","endLine":828,"endColumn":95,"suggestions":"2046"},{"ruleId":"1773","severity":1,"message":"1774","line":846,"column":54,"nodeType":"1775","messageId":"1776","endLine":846,"endColumn":57,"suggestions":"2047"},{"ruleId":"1773","severity":1,"message":"1774","line":846,"column":84,"nodeType":"1775","messageId":"1776","endLine":846,"endColumn":87,"suggestions":"2048"},{"ruleId":"1770","severity":1,"message":"2049","line":38,"column":44,"nodeType":"1766","messageId":"1772","endLine":38,"endColumn":52},{"ruleId":"1929","severity":2,"message":"1930","line":39,"column":35,"nodeType":"1766","messageId":"1931","endLine":39,"endColumn":40},{"ruleId":"1770","severity":1,"message":"1932","line":48,"column":58,"nodeType":"1766","messageId":"1772","endLine":48,"endColumn":62},{"ruleId":"1770","severity":1,"message":"1933","line":48,"column":64,"nodeType":"1766","messageId":"1772","endLine":48,"endColumn":69},{"ruleId":"1859","severity":2,"message":"1860","line":162,"column":11,"nodeType":"1766","messageId":"1861","endLine":162,"endColumn":15},{"ruleId":"1784","severity":1,"message":"1785","line":165,"column":20,"nodeType":"1786","messageId":"1787","endLine":165,"endColumn":29},{"ruleId":"1859","severity":2,"message":"1860","line":166,"column":15,"nodeType":"1766","messageId":"1861","endLine":166,"endColumn":22},{"ruleId":"1773","severity":1,"message":"1774","line":209,"column":35,"nodeType":"1775","messageId":"1776","endLine":209,"endColumn":38,"suggestions":"2050"},{"ruleId":"1773","severity":1,"message":"1774","line":210,"column":37,"nodeType":"1775","messageId":"1776","endLine":210,"endColumn":40,"suggestions":"2051"},{"ruleId":"1859","severity":2,"message":"1860","line":249,"column":11,"nodeType":"1766","messageId":"1861","endLine":249,"endColumn":15},{"ruleId":"1784","severity":1,"message":"1785","line":252,"column":30,"nodeType":"1786","messageId":"1787","endLine":252,"endColumn":39},{"ruleId":"1859","severity":2,"message":"1860","line":253,"column":13,"nodeType":"1766","messageId":"1861","endLine":253,"endColumn":20},{"ruleId":"1784","severity":1,"message":"1785","line":258,"column":35,"nodeType":"1786","messageId":"1787","endLine":258,"endColumn":44},{"ruleId":"1859","severity":2,"message":"1860","line":259,"column":13,"nodeType":"1766","messageId":"1861","endLine":259,"endColumn":20},{"ruleId":"1784","severity":1,"message":"1785","line":265,"column":33,"nodeType":"1786","messageId":"1787","endLine":265,"endColumn":42},{"ruleId":"1770","severity":1,"message":"1790","line":330,"column":28,"nodeType":"1766","messageId":"1772","endLine":330,"endColumn":33},{"ruleId":"1922","severity":2,"message":"1923","line":342,"column":38,"nodeType":"1766","messageId":"1924","endLine":342,"endColumn":43},{"ruleId":"1922","severity":2,"message":"1923","line":345,"column":38,"nodeType":"1766","messageId":"1924","endLine":345,"endColumn":43},{"ruleId":"1922","severity":2,"message":"1923","line":366,"column":60,"nodeType":"1766","messageId":"1924","endLine":366,"endColumn":65},{"ruleId":"1922","severity":2,"message":"1923","line":370,"column":39,"nodeType":"1766","messageId":"1924","endLine":370,"endColumn":44},{"ruleId":"1859","severity":2,"message":"1860","line":399,"column":15,"nodeType":"1766","messageId":"1861","endLine":399,"endColumn":19},{"ruleId":"1784","severity":1,"message":"1785","line":400,"column":29,"nodeType":"1786","messageId":"1787","endLine":400,"endColumn":38},{"ruleId":"1859","severity":2,"message":"1860","line":401,"column":17,"nodeType":"1766","messageId":"1861","endLine":401,"endColumn":24},{"ruleId":"1848","severity":1,"message":"1849","line":409,"column":18,"nodeType":"1850","messageId":"1851","endLine":409,"endColumn":67},{"ruleId":"1812","severity":1,"message":"2052","line":409,"column":30,"nodeType":"1766","messageId":"1814","endLine":409,"endColumn":34},{"ruleId":"1770","severity":1,"message":"1968","line":413,"column":30,"nodeType":"1766","messageId":"1772","endLine":413,"endColumn":35},{"ruleId":"1812","severity":1,"message":"1965","line":459,"column":7,"nodeType":"1766","messageId":"1814","endLine":459,"endColumn":12},{"ruleId":"1960","severity":2,"message":"1961","line":20,"column":32,"nodeType":"1766","messageId":"1962","endLine":20,"endColumn":38},{"ruleId":"1770","severity":1,"message":"2053","line":873,"column":13,"nodeType":"1766","messageId":"1772","endLine":873,"endColumn":19},{"ruleId":"1773","severity":1,"message":"1774","line":1031,"column":12,"nodeType":"1775","messageId":"1776","endLine":1031,"endColumn":15,"suggestions":"2054"},{"ruleId":"1773","severity":1,"message":"1774","line":1035,"column":9,"nodeType":"1775","messageId":"1776","endLine":1035,"endColumn":12,"suggestions":"2055"},{"ruleId":"1773","severity":1,"message":"1774","line":1037,"column":20,"nodeType":"1775","messageId":"1776","endLine":1037,"endColumn":23,"suggestions":"2056"},{"ruleId":"1773","severity":1,"message":"1774","line":1039,"column":14,"nodeType":"1775","messageId":"1776","endLine":1039,"endColumn":17,"suggestions":"2057"},{"ruleId":"1773","severity":1,"message":"1774","line":1041,"column":13,"nodeType":"1775","messageId":"1776","endLine":1041,"endColumn":16,"suggestions":"2058"},{"ruleId":"1960","severity":2,"message":"1961","line":1045,"column":32,"nodeType":"1766","messageId":"1962","endLine":1045,"endColumn":38},{"ruleId":"1773","severity":1,"message":"1774","line":1052,"column":41,"nodeType":"1775","messageId":"1776","endLine":1052,"endColumn":44,"suggestions":"2059"},{"ruleId":"1773","severity":1,"message":"1774","line":1053,"column":41,"nodeType":"1775","messageId":"1776","endLine":1053,"endColumn":44,"suggestions":"2060"},{"ruleId":"1773","severity":1,"message":"1774","line":1068,"column":32,"nodeType":"1775","messageId":"1776","endLine":1068,"endColumn":35,"suggestions":"2061"},{"ruleId":"2062","severity":2,"message":"2063","line":1068,"column":36,"nodeType":"2064","messageId":"1844","endLine":1068,"endColumn":115},{"ruleId":"2065","severity":2,"message":"2066","line":1068,"column":36,"nodeType":"2064","messageId":"2067","endLine":1068,"endColumn":115},{"ruleId":"1773","severity":1,"message":"1774","line":1069,"column":55,"nodeType":"1775","messageId":"1776","endLine":1069,"endColumn":58,"suggestions":"2068"},{"ruleId":"1950","severity":2,"message":"1951","line":1070,"column":30,"nodeType":"1952","messageId":"1953","endLine":1070,"endColumn":41},{"ruleId":"1773","severity":1,"message":"1774","line":1081,"column":30,"nodeType":"1775","messageId":"1776","endLine":1081,"endColumn":33,"suggestions":"2069"},{"ruleId":"2062","severity":2,"message":"2063","line":1081,"column":34,"nodeType":"2064","messageId":"1844","endLine":1081,"endColumn":102},{"ruleId":"2065","severity":2,"message":"2066","line":1081,"column":34,"nodeType":"2064","messageId":"2067","endLine":1081,"endColumn":102},{"ruleId":"1773","severity":1,"message":"1774","line":1082,"column":50,"nodeType":"1775","messageId":"1776","endLine":1082,"endColumn":53,"suggestions":"2070"},{"ruleId":"1950","severity":2,"message":"1951","line":1083,"column":32,"nodeType":"1952","messageId":"1953","endLine":1083,"endColumn":41},{"ruleId":"1770","severity":1,"message":"2071","line":1185,"column":19,"nodeType":"1766","messageId":"1772","endLine":1185,"endColumn":36},{"ruleId":"1770","severity":1,"message":"2072","line":1,"column":31,"nodeType":"1766","messageId":"1772","endLine":1,"endColumn":40},{"ruleId":"1770","severity":1,"message":"2072","line":1,"column":31,"nodeType":"1766","messageId":"1772","endLine":1,"endColumn":40},{"ruleId":"1812","severity":1,"message":"2073","line":30,"column":5,"nodeType":"1766","messageId":"1814","endLine":30,"endColumn":11},{"ruleId":"1773","severity":1,"message":"1774","line":12,"column":22,"nodeType":"1775","messageId":"1776","endLine":12,"endColumn":25,"suggestions":"2074"},{"ruleId":"2075","severity":2,"message":"2076","line":15,"column":25,"nodeType":"1857","messageId":"2077","endLine":15,"endColumn":30},{"ruleId":"1773","severity":1,"message":"1774","line":41,"column":53,"nodeType":"1775","messageId":"1776","endLine":41,"endColumn":56,"suggestions":"2078"},{"ruleId":"1773","severity":1,"message":"1774","line":47,"column":56,"nodeType":"1775","messageId":"1776","endLine":47,"endColumn":59,"suggestions":"2079"},{"ruleId":"1770","severity":1,"message":"2080","line":167,"column":13,"nodeType":"1766","messageId":"1772","endLine":167,"endColumn":21},{"ruleId":"1859","severity":2,"message":"1860","line":249,"column":11,"nodeType":"1766","messageId":"1861","endLine":249,"endColumn":15},{"ruleId":"1784","severity":1,"message":"2081","line":260,"column":20,"nodeType":"1786","messageId":"1787","endLine":260,"endColumn":35},{"ruleId":"1795","severity":2,"message":"2082","line":263,"column":15,"nodeType":"1766","messageId":"1797","endLine":263,"endColumn":35},{"ruleId":"1770","severity":1,"message":"2083","line":286,"column":13,"nodeType":"1766","messageId":"1772","endLine":286,"endColumn":20},{"ruleId":"1812","severity":1,"message":"2084","line":291,"column":5,"nodeType":"1766","messageId":"1814","endLine":291,"endColumn":15},{"ruleId":"1773","severity":1,"message":"1774","line":299,"column":46,"nodeType":"1775","messageId":"1776","endLine":299,"endColumn":49,"suggestions":"2085"},{"ruleId":"1773","severity":1,"message":"1774","line":300,"column":26,"nodeType":"1775","messageId":"1776","endLine":300,"endColumn":29,"suggestions":"2086"},{"ruleId":"1773","severity":1,"message":"1774","line":311,"column":41,"nodeType":"1775","messageId":"1776","endLine":311,"endColumn":44,"suggestions":"2087"},{"ruleId":"1773","severity":1,"message":"1774","line":495,"column":84,"nodeType":"1775","messageId":"1776","endLine":495,"endColumn":87,"suggestions":"2088"},{"ruleId":"1770","severity":1,"message":"1790","line":520,"column":38,"nodeType":"1766","messageId":"1772","endLine":520,"endColumn":43},{"ruleId":"1770","severity":1,"message":"1790","line":528,"column":38,"nodeType":"1766","messageId":"1772","endLine":528,"endColumn":43},{"ruleId":"1770","severity":1,"message":"1790","line":535,"column":38,"nodeType":"1766","messageId":"1772","endLine":535,"endColumn":43},{"ruleId":"1848","severity":1,"message":"1849","line":23,"column":58,"nodeType":"1850","messageId":"1851","endLine":23,"endColumn":89},{"ruleId":"1812","severity":1,"message":"1880","line":23,"column":68,"nodeType":"1766","messageId":"1814","endLine":23,"endColumn":71},{"ruleId":"1848","severity":1,"message":"1849","line":48,"column":28,"nodeType":"1850","messageId":"1851","endLine":48,"endColumn":59},{"ruleId":"1812","severity":1,"message":"1880","line":48,"column":38,"nodeType":"1766","messageId":"1814","endLine":48,"endColumn":41},{"ruleId":"1848","severity":1,"message":"1849","line":77,"column":30,"nodeType":"1850","messageId":"1851","endLine":77,"endColumn":60},{"ruleId":"1812","severity":1,"message":"1880","line":77,"column":40,"nodeType":"1766","messageId":"1814","endLine":77,"endColumn":43},{"ruleId":"1773","severity":1,"message":"1774","line":102,"column":18,"nodeType":"1775","messageId":"1776","endLine":102,"endColumn":21,"suggestions":"2089"},{"ruleId":"1773","severity":1,"message":"1774","line":230,"column":38,"nodeType":"1775","messageId":"1776","endLine":230,"endColumn":41,"suggestions":"2090"},{"ruleId":"1773","severity":1,"message":"1774","line":252,"column":29,"nodeType":"1775","messageId":"1776","endLine":252,"endColumn":32,"suggestions":"2091"},{"ruleId":"1773","severity":1,"message":"1774","line":273,"column":29,"nodeType":"1775","messageId":"1776","endLine":273,"endColumn":32,"suggestions":"2092"},{"ruleId":"1773","severity":1,"message":"1774","line":63,"column":72,"nodeType":"1775","messageId":"1776","endLine":63,"endColumn":75,"suggestions":"2093"},{"ruleId":"1812","severity":1,"message":"2094","line":70,"column":9,"nodeType":"1766","messageId":"1901","endLine":70,"endColumn":15},{"ruleId":"1812","severity":1,"message":"2094","line":73,"column":9,"nodeType":"1766","messageId":"1901","endLine":73,"endColumn":15},{"ruleId":"1812","severity":1,"message":"2094","line":80,"column":9,"nodeType":"1766","messageId":"1901","endLine":80,"endColumn":15},{"ruleId":"1812","severity":1,"message":"2094","line":83,"column":9,"nodeType":"1766","messageId":"1901","endLine":83,"endColumn":15},{"ruleId":"1812","severity":1,"message":"2095","line":100,"column":5,"nodeType":"1766","messageId":"1814","endLine":100,"endColumn":11},{"ruleId":"1812","severity":1,"message":"2095","line":223,"column":10,"nodeType":"1766","messageId":"1814","endLine":223,"endColumn":16},{"ruleId":"1812","severity":1,"message":"2095","line":240,"column":10,"nodeType":"1766","messageId":"1814","endLine":240,"endColumn":16},{"ruleId":"1812","severity":1,"message":"2095","line":249,"column":10,"nodeType":"1766","messageId":"1814","endLine":249,"endColumn":16},{"ruleId":"1969","severity":2,"message":"2096","line":376,"column":1,"nodeType":null,"messageId":"2097","endLine":377,"endColumn":1,"fix":"2098"},{"ruleId":"1812","severity":1,"message":"2095","line":410,"column":3,"nodeType":"1766","messageId":"1814","endLine":410,"endColumn":9},{"ruleId":"1937","severity":1,"message":"1938","line":57,"column":35,"nodeType":"1939","messageId":"1940","endLine":57,"endColumn":54},{"ruleId":"1937","severity":1,"message":"1938","line":90,"column":35,"nodeType":"1939","messageId":"1940","endLine":90,"endColumn":54},{"ruleId":"1937","severity":1,"message":"1938","line":125,"column":33,"nodeType":"1939","messageId":"1940","endLine":125,"endColumn":52},{"ruleId":"1937","severity":1,"message":"1938","line":126,"column":75,"nodeType":"1939","messageId":"1940","endLine":126,"endColumn":94},{"ruleId":"1937","severity":1,"message":"1938","line":128,"column":53,"nodeType":"1939","messageId":"1940","endLine":128,"endColumn":72},{"ruleId":"1937","severity":1,"message":"1938","line":190,"column":33,"nodeType":"1939","messageId":"1940","endLine":190,"endColumn":52},{"ruleId":"1773","severity":1,"message":"1774","line":51,"column":18,"nodeType":"1775","messageId":"1776","endLine":51,"endColumn":21,"suggestions":"2099"},{"ruleId":"2100","severity":2,"message":"2101","line":243,"column":17,"nodeType":"2102","messageId":"2103","endLine":243,"endColumn":33},{"ruleId":"1773","severity":1,"message":"1774","line":243,"column":40,"nodeType":"1775","messageId":"1776","endLine":243,"endColumn":43,"suggestions":"2104"},{"ruleId":"1837","severity":2,"message":"1838","line":254,"column":3,"nodeType":"1839","messageId":"1840","endLine":261,"endColumn":4},{"ruleId":"1764","severity":2,"message":"2105","line":352,"column":19,"nodeType":"1766","messageId":"1767","endLine":352,"endColumn":37},{"ruleId":"1764","severity":2,"message":"2105","line":371,"column":19,"nodeType":"1766","messageId":"1767","endLine":371,"endColumn":37},{"ruleId":"1764","severity":2,"message":"2105","line":389,"column":19,"nodeType":"1766","messageId":"1767","endLine":389,"endColumn":37},{"ruleId":"1773","severity":1,"message":"1774","line":499,"column":57,"nodeType":"1775","messageId":"1776","endLine":499,"endColumn":60,"suggestions":"2106"},{"ruleId":"1764","severity":2,"message":"2107","line":509,"column":10,"nodeType":"1766","messageId":"1767","endLine":509,"endColumn":26},{"ruleId":"1837","severity":2,"message":"1838","line":515,"column":3,"nodeType":"1839","messageId":"1840","endLine":531,"endColumn":4},{"ruleId":"1795","severity":2,"message":"2108","line":250,"column":31,"nodeType":"1766","messageId":"1797","endLine":250,"endColumn":32},{"ruleId":"1795","severity":2,"message":"2108","line":266,"column":31,"nodeType":"1766","messageId":"1797","endLine":266,"endColumn":32},{"ruleId":"1795","severity":2,"message":"2108","line":282,"column":31,"nodeType":"1766","messageId":"1797","endLine":282,"endColumn":32},{"ruleId":"1795","severity":2,"message":"2108","line":298,"column":31,"nodeType":"1766","messageId":"1797","endLine":298,"endColumn":32},{"ruleId":"1795","severity":2,"message":"2108","line":314,"column":31,"nodeType":"1766","messageId":"1797","endLine":314,"endColumn":32},{"ruleId":"1795","severity":2,"message":"2109","line":335,"column":31,"nodeType":"1766","messageId":"1797","endLine":335,"endColumn":32},{"ruleId":"1795","severity":2,"message":"2109","line":351,"column":31,"nodeType":"1766","messageId":"1797","endLine":351,"endColumn":32},{"ruleId":"1795","severity":2,"message":"2109","line":367,"column":31,"nodeType":"1766","messageId":"1797","endLine":367,"endColumn":32},{"ruleId":"1795","severity":2,"message":"2109","line":383,"column":31,"nodeType":"1766","messageId":"1797","endLine":383,"endColumn":32},{"ruleId":"1795","severity":2,"message":"2109","line":399,"column":31,"nodeType":"1766","messageId":"1797","endLine":399,"endColumn":32},{"ruleId":"1795","severity":2,"message":"2110","line":436,"column":35,"nodeType":"1766","messageId":"1797","endLine":436,"endColumn":36},{"ruleId":"1795","severity":2,"message":"2110","line":452,"column":35,"nodeType":"1766","messageId":"1797","endLine":452,"endColumn":36},{"ruleId":"1795","severity":2,"message":"2110","line":468,"column":35,"nodeType":"1766","messageId":"1797","endLine":468,"endColumn":36},{"ruleId":"1773","severity":1,"message":"1774","line":536,"column":13,"nodeType":"1775","messageId":"1776","endLine":536,"endColumn":16,"suggestions":"2111"},{"ruleId":"1773","severity":1,"message":"1774","line":540,"column":29,"nodeType":"1775","messageId":"1776","endLine":540,"endColumn":32,"suggestions":"2112"},{"ruleId":"1764","severity":2,"message":"2113","line":575,"column":16,"nodeType":"1766","messageId":"1767","endLine":575,"endColumn":30},{"ruleId":"1764","severity":2,"message":"2114","line":575,"column":31,"nodeType":"1766","messageId":"1767","endLine":575,"endColumn":54},{"ruleId":"1764","severity":2,"message":"2113","line":578,"column":16,"nodeType":"1766","messageId":"1767","endLine":578,"endColumn":30},{"ruleId":"1764","severity":2,"message":"2114","line":578,"column":31,"nodeType":"1766","messageId":"1767","endLine":578,"endColumn":54},{"ruleId":"1773","severity":1,"message":"1774","line":597,"column":53,"nodeType":"1775","messageId":"1776","endLine":597,"endColumn":56,"suggestions":"2115"},{"ruleId":"1773","severity":1,"message":"1774","line":597,"column":76,"nodeType":"1775","messageId":"1776","endLine":597,"endColumn":79,"suggestions":"2116"},{"ruleId":"1770","severity":1,"message":"1899","line":57,"column":37,"nodeType":"1766","messageId":"1772","endLine":57,"endColumn":58},{"ruleId":"1770","severity":1,"message":"1899","line":62,"column":25,"nodeType":"1766","messageId":"1772","endLine":62,"endColumn":46},{"ruleId":"1770","severity":1,"message":"2117","line":62,"column":48,"nodeType":"1766","messageId":"1772","endLine":62,"endColumn":61},{"ruleId":"1770","severity":1,"message":"1899","line":89,"column":32,"nodeType":"1766","messageId":"1772","endLine":89,"endColumn":53},{"ruleId":"1770","severity":1,"message":"1899","line":152,"column":37,"nodeType":"1766","messageId":"1772","endLine":152,"endColumn":58},{"ruleId":"1764","severity":2,"message":"2118","line":234,"column":31,"nodeType":"1766","messageId":"1767","endLine":234,"endColumn":43},{"ruleId":"1770","severity":1,"message":"2119","line":254,"column":11,"nodeType":"1766","messageId":"1772","endLine":254,"endColumn":20},{"ruleId":"1770","severity":1,"message":"2120","line":255,"column":11,"nodeType":"1766","messageId":"1772","endLine":255,"endColumn":23},{"ruleId":"1812","severity":1,"message":"2121","line":343,"column":9,"nodeType":"1766","messageId":"1901","endLine":343,"endColumn":16},{"ruleId":"1812","severity":1,"message":"2122","line":344,"column":9,"nodeType":"1766","messageId":"1814","endLine":344,"endColumn":16},{"ruleId":"1812","severity":1,"message":"2121","line":346,"column":9,"nodeType":"1766","messageId":"1901","endLine":346,"endColumn":16},{"ruleId":"1770","severity":1,"message":"1899","line":358,"column":31,"nodeType":"1766","messageId":"1772","endLine":358,"endColumn":52},{"ruleId":"1770","severity":1,"message":"2117","line":358,"column":54,"nodeType":"1766","messageId":"1772","endLine":358,"endColumn":67},{"ruleId":"1770","severity":1,"message":"1899","line":400,"column":37,"nodeType":"1766","messageId":"1772","endLine":400,"endColumn":58},{"ruleId":"1770","severity":1,"message":"1899","line":416,"column":31,"nodeType":"1766","messageId":"1772","endLine":416,"endColumn":52},{"ruleId":"1770","severity":1,"message":"2117","line":416,"column":54,"nodeType":"1766","messageId":"1772","endLine":416,"endColumn":67},{"ruleId":"1773","severity":1,"message":"1774","line":433,"column":46,"nodeType":"1775","messageId":"1776","endLine":433,"endColumn":49,"suggestions":"2123"},{"ruleId":"1764","severity":2,"message":"2124","line":471,"column":10,"nodeType":"1766","messageId":"1767","endLine":471,"endColumn":30},{"ruleId":"1868","severity":2,"message":"1869","line":485,"column":17,"nodeType":"1870","messageId":"1871","endLine":485,"endColumn":74},{"ruleId":"1773","severity":1,"message":"1774","line":20,"column":20,"nodeType":"1775","messageId":"1776","endLine":20,"endColumn":23,"suggestions":"2125"},{"ruleId":"1773","severity":1,"message":"1774","line":49,"column":18,"nodeType":"1775","messageId":"1776","endLine":49,"endColumn":21,"suggestions":"2126"},{"ruleId":"1883","severity":2,"message":"2127","line":8,"column":10,"nodeType":"1766","endLine":8,"endColumn":23},{"ruleId":"1770","severity":1,"message":"2128","line":102,"column":13,"nodeType":"1766","messageId":"1772","endLine":102,"endColumn":35},{"ruleId":"1770","severity":1,"message":"1899","line":179,"column":37,"nodeType":"1766","messageId":"1772","endLine":179,"endColumn":58},{"ruleId":"1812","severity":1,"message":"2129","line":218,"column":11,"nodeType":"1766","messageId":"1814","endLine":218,"endColumn":14},{"ruleId":"1770","severity":1,"message":"1899","line":256,"column":31,"nodeType":"1766","messageId":"1772","endLine":256,"endColumn":52},{"ruleId":"1770","severity":1,"message":"2117","line":256,"column":54,"nodeType":"1766","messageId":"1772","endLine":256,"endColumn":67},{"ruleId":"1812","severity":1,"message":"1881","line":303,"column":9,"nodeType":"1766","messageId":"1814","endLine":303,"endColumn":13},{"ruleId":"1770","severity":1,"message":"2130","line":313,"column":5,"nodeType":"1766","messageId":"1772","endLine":313,"endColumn":28},{"ruleId":"1770","severity":1,"message":"2131","line":314,"column":5,"nodeType":"1766","messageId":"1772","endLine":314,"endColumn":122},{"ruleId":"1770","severity":1,"message":"2132","line":319,"column":12,"nodeType":"1766","messageId":"1772","endLine":319,"endColumn":30},{"ruleId":"1770","severity":1,"message":"1899","line":319,"column":32,"nodeType":"1766","messageId":"1772","endLine":319,"endColumn":53},{"ruleId":"2100","severity":2,"message":"2133","line":323,"column":3,"nodeType":"1786","messageId":"2103","endLine":323,"endColumn":9},{"ruleId":"1960","severity":2,"message":"2134","line":344,"column":47,"nodeType":"1766","messageId":"1962","endLine":344,"endColumn":55},{"ruleId":"1906","severity":2,"message":"2135","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2137","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2138","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2139","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2140","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2141","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2142","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2143","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2144","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2145","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2146","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2147","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2148","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2149","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2150","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2151","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2152","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2153","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2154","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2155","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2156","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2157","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2158","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2159","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2160","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2161","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2162","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2163","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2164","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2165","line":1,"column":1,"nodeType":"2136","endLine":1,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2135","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2137","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2138","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2139","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2140","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2141","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2142","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2143","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2144","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2145","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2146","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2147","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2148","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2149","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2150","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2151","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2152","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2153","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2154","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2155","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2156","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2157","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2158","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2159","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2160","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2161","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2162","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2163","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2164","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1906","severity":2,"message":"2165","line":6,"column":1,"nodeType":"2136","endLine":6,"endColumn":23},{"ruleId":"1784","severity":1,"message":"1785","line":8,"column":16,"nodeType":"2102","messageId":"1787","endLine":8,"endColumn":25},{"ruleId":"1773","severity":1,"message":"1774","line":11,"column":70,"nodeType":"1775","messageId":"1776","endLine":11,"endColumn":73,"suggestions":"2166"},{"ruleId":"1960","severity":2,"message":"2167","line":11,"column":85,"nodeType":"2168","messageId":"1962","endLine":11,"endColumn":87},{"ruleId":"1770","severity":1,"message":"2169","line":18,"column":12,"nodeType":"1766","messageId":"1772","endLine":18,"endColumn":28},{"ruleId":"1773","severity":1,"message":"1774","line":18,"column":89,"nodeType":"1775","messageId":"1776","endLine":18,"endColumn":92,"suggestions":"2170"},{"ruleId":"1773","severity":1,"message":"1774","line":34,"column":42,"nodeType":"1775","messageId":"1776","endLine":34,"endColumn":45,"suggestions":"2171"},{"ruleId":"1773","severity":1,"message":"1774","line":37,"column":22,"nodeType":"1775","messageId":"1776","endLine":37,"endColumn":25,"suggestions":"2172"},{"ruleId":"1773","severity":1,"message":"1774","line":38,"column":16,"nodeType":"1775","messageId":"1776","endLine":38,"endColumn":19,"suggestions":"2173"},{"ruleId":"1773","severity":1,"message":"1774","line":41,"column":23,"nodeType":"1775","messageId":"1776","endLine":41,"endColumn":26,"suggestions":"2174"},{"ruleId":"1773","severity":1,"message":"1774","line":41,"column":40,"nodeType":"1775","messageId":"1776","endLine":41,"endColumn":43,"suggestions":"2175"},{"ruleId":"1773","severity":1,"message":"1774","line":41,"column":52,"nodeType":"1775","messageId":"1776","endLine":41,"endColumn":55,"suggestions":"2176"},{"ruleId":"1773","severity":1,"message":"1774","line":45,"column":49,"nodeType":"1775","messageId":"1776","endLine":45,"endColumn":52,"suggestions":"2177"},{"ruleId":"1773","severity":1,"message":"1774","line":45,"column":78,"nodeType":"1775","messageId":"1776","endLine":45,"endColumn":81,"suggestions":"2178"},{"ruleId":"1773","severity":1,"message":"1774","line":47,"column":24,"nodeType":"1775","messageId":"1776","endLine":47,"endColumn":27,"suggestions":"2179"},{"ruleId":"1773","severity":1,"message":"1774","line":140,"column":59,"nodeType":"1775","messageId":"1776","endLine":140,"endColumn":62,"suggestions":"2180"},{"ruleId":"1773","severity":1,"message":"1774","line":151,"column":62,"nodeType":"1775","messageId":"1776","endLine":151,"endColumn":65,"suggestions":"2181"},{"ruleId":"2182","severity":2,"message":"2183","line":182,"column":37,"nodeType":"2064","messageId":"2184","endLine":182,"endColumn":64},{"ruleId":"1770","severity":1,"message":"2185","line":15,"column":9,"nodeType":"1766","messageId":"1772","endLine":15,"endColumn":18},{"ruleId":"1773","severity":1,"message":"1774","line":45,"column":54,"nodeType":"1775","messageId":"1776","endLine":45,"endColumn":57,"suggestions":"2186"},{"ruleId":"1770","severity":1,"message":"2187","line":97,"column":11,"nodeType":"1766","messageId":"1772","endLine":97,"endColumn":16},{"ruleId":"2188","severity":1,"message":"2189","line":195,"column":19,"nodeType":"2064","messageId":"2190","endLine":195,"endColumn":33},{"ruleId":"2188","severity":1,"message":"2189","line":205,"column":21,"nodeType":"2064","messageId":"2190","endLine":205,"endColumn":35},{"ruleId":"2188","severity":1,"message":"2189","line":303,"column":19,"nodeType":"2064","messageId":"2190","endLine":303,"endColumn":33},{"ruleId":"2188","severity":1,"message":"2189","line":313,"column":23,"nodeType":"2064","messageId":"2190","endLine":313,"endColumn":37},{"ruleId":"1770","severity":1,"message":"1771","line":470,"column":9,"nodeType":"1766","messageId":"1772","endLine":470,"endColumn":13},{"ruleId":"1773","severity":1,"message":"1774","line":872,"column":40,"nodeType":"1775","messageId":"1776","endLine":872,"endColumn":43,"suggestions":"2191"},{"ruleId":"1764","severity":2,"message":"1765","line":96,"column":11,"nodeType":"1766","messageId":"1767","endLine":96,"endColumn":29,"suppressions":"2192"},{"ruleId":"1764","severity":2,"message":"1768","line":104,"column":22,"nodeType":"1766","messageId":"1767","endLine":104,"endColumn":45,"suppressions":"2193"},{"ruleId":"1764","severity":2,"message":"1769","line":107,"column":19,"nodeType":"1766","messageId":"1767","endLine":107,"endColumn":25,"suppressions":"2194"},{"ruleId":"1764","severity":2,"message":"1765","line":144,"column":11,"nodeType":"1766","messageId":"1767","endLine":144,"endColumn":29,"suppressions":"2195"},{"ruleId":"1764","severity":2,"message":"1768","line":150,"column":22,"nodeType":"1766","messageId":"1767","endLine":150,"endColumn":45,"suppressions":"2196"},{"ruleId":"1764","severity":2,"message":"1769","line":155,"column":19,"nodeType":"1766","messageId":"1767","endLine":155,"endColumn":25,"suppressions":"2197"},{"ruleId":"1764","severity":2,"message":"1765","line":182,"column":11,"nodeType":"1766","messageId":"1767","endLine":182,"endColumn":29,"suppressions":"2198"},{"ruleId":"1764","severity":2,"message":"1768","line":188,"column":22,"nodeType":"1766","messageId":"1767","endLine":188,"endColumn":45,"suppressions":"2199"},{"ruleId":"1764","severity":2,"message":"1769","line":193,"column":19,"nodeType":"1766","messageId":"1767","endLine":193,"endColumn":25,"suppressions":"2200"},{"ruleId":"1764","severity":2,"message":"1765","line":219,"column":11,"nodeType":"1766","messageId":"1767","endLine":219,"endColumn":29,"suppressions":"2201"},{"ruleId":"1764","severity":2,"message":"1768","line":224,"column":22,"nodeType":"1766","messageId":"1767","endLine":224,"endColumn":45,"suppressions":"2202"},{"ruleId":"1764","severity":2,"message":"1769","line":229,"column":19,"nodeType":"1766","messageId":"1767","endLine":229,"endColumn":25,"suppressions":"2203"},{"ruleId":"1764","severity":2,"message":"1765","line":257,"column":11,"nodeType":"1766","messageId":"1767","endLine":257,"endColumn":29,"suppressions":"2204"},{"ruleId":"1764","severity":2,"message":"1768","line":264,"column":22,"nodeType":"1766","messageId":"1767","endLine":264,"endColumn":45,"suppressions":"2205"},{"ruleId":"1764","severity":2,"message":"1769","line":270,"column":19,"nodeType":"1766","messageId":"1767","endLine":270,"endColumn":25,"suppressions":"2206"},{"ruleId":"1764","severity":2,"message":"1765","line":299,"column":11,"nodeType":"1766","messageId":"1767","endLine":299,"endColumn":29,"suppressions":"2207"},{"ruleId":"1764","severity":2,"message":"1768","line":307,"column":22,"nodeType":"1766","messageId":"1767","endLine":307,"endColumn":45,"suppressions":"2208"},{"ruleId":"1764","severity":2,"message":"1769","line":313,"column":19,"nodeType":"1766","messageId":"1767","endLine":313,"endColumn":25,"suppressions":"2209"},{"ruleId":"1764","severity":2,"message":"1765","line":342,"column":11,"nodeType":"1766","messageId":"1767","endLine":342,"endColumn":29,"suppressions":"2210"},{"ruleId":"1764","severity":2,"message":"1768","line":350,"column":22,"nodeType":"1766","messageId":"1767","endLine":350,"endColumn":45,"suppressions":"2211"},{"ruleId":"1764","severity":2,"message":"1769","line":356,"column":19,"nodeType":"1766","messageId":"1767","endLine":356,"endColumn":25,"suppressions":"2212"},{"ruleId":"1764","severity":2,"message":"1765","line":382,"column":11,"nodeType":"1766","messageId":"1767","endLine":382,"endColumn":29,"suppressions":"2213"},{"ruleId":"1764","severity":2,"message":"1768","line":387,"column":22,"nodeType":"1766","messageId":"1767","endLine":387,"endColumn":45,"suppressions":"2214"},{"ruleId":"1764","severity":2,"message":"1769","line":393,"column":19,"nodeType":"1766","messageId":"1767","endLine":393,"endColumn":25,"suppressions":"2215"},{"ruleId":"1764","severity":2,"message":"1769","line":469,"column":19,"nodeType":"1766","messageId":"1767","endLine":469,"endColumn":25,"suppressions":"2216"},{"ruleId":"1770","severity":1,"message":"1778","line":3,"column":10,"nodeType":"1766","messageId":"1772","endLine":3,"endColumn":27},{"ruleId":"1773","severity":1,"message":"1774","line":28,"column":23,"nodeType":"1775","messageId":"1776","endLine":28,"endColumn":26,"suggestions":"2217"},{"ruleId":"1770","severity":1,"message":"1780","line":55,"column":19,"nodeType":"1766","messageId":"1772","endLine":55,"endColumn":33},{"ruleId":"1770","severity":1,"message":"1781","line":55,"column":35,"nodeType":"1766","messageId":"1772","endLine":55,"endColumn":48},{"ruleId":"1773","severity":1,"message":"1774","line":174,"column":35,"nodeType":"1775","messageId":"1776","endLine":174,"endColumn":38,"suggestions":"2218"},{"ruleId":"1773","severity":1,"message":"1774","line":195,"column":41,"nodeType":"1775","messageId":"1776","endLine":195,"endColumn":44,"suggestions":"2219"},{"ruleId":"1784","severity":1,"message":"1785","line":214,"column":7,"nodeType":"1786","messageId":"1787","endLine":214,"endColumn":16},{"ruleId":"1773","severity":1,"message":"1774","line":227,"column":53,"nodeType":"1775","messageId":"1776","endLine":227,"endColumn":56,"suggestions":"2220"},{"ruleId":"1773","severity":1,"message":"1774","line":234,"column":58,"nodeType":"1775","messageId":"1776","endLine":234,"endColumn":61,"suggestions":"2221"},{"ruleId":"1770","severity":1,"message":"1790","line":273,"column":38,"nodeType":"1766","messageId":"1772","endLine":273,"endColumn":43},{"ruleId":"1773","severity":1,"message":"1774","line":385,"column":111,"nodeType":"1775","messageId":"1776","endLine":385,"endColumn":114,"suggestions":"2222"},{"ruleId":"1773","severity":1,"message":"1774","line":405,"column":121,"nodeType":"1775","messageId":"1776","endLine":405,"endColumn":124,"suggestions":"2223"},{"ruleId":"1773","severity":1,"message":"1774","line":427,"column":52,"nodeType":"1775","messageId":"1776","endLine":427,"endColumn":55,"suggestions":"2224"},{"ruleId":"1773","severity":1,"message":"1774","line":445,"column":46,"nodeType":"1775","messageId":"1776","endLine":445,"endColumn":49,"suggestions":"2225"},{"ruleId":"1770","severity":1,"message":"1798","line":530,"column":9,"nodeType":"1766","messageId":"1772","endLine":530,"endColumn":18},{"ruleId":"1773","severity":1,"message":"1774","line":9,"column":32,"nodeType":"1775","messageId":"1776","endLine":9,"endColumn":35,"suggestions":"2226"},{"ruleId":"1764","severity":2,"message":"1804","line":30,"column":7,"nodeType":"1766","messageId":"1767","endLine":30,"endColumn":26,"suppressions":"2227"},{"ruleId":"1773","severity":1,"message":"1774","line":55,"column":26,"nodeType":"1775","messageId":"1776","endLine":55,"endColumn":29,"suggestions":"2228"},{"ruleId":"1770","severity":1,"message":"1806","line":117,"column":34,"nodeType":"1766","messageId":"1772","endLine":117,"endColumn":36},{"ruleId":"1770","severity":1,"message":"1807","line":126,"column":32,"nodeType":"1766","messageId":"1772","endLine":126,"endColumn":60},{"ruleId":"1770","severity":1,"message":"1808","line":848,"column":17,"nodeType":"1766","messageId":"1772","endLine":848,"endColumn":26},{"ruleId":"1770","severity":1,"message":"1790","line":929,"column":49,"nodeType":"1766","messageId":"1772","endLine":929,"endColumn":54},{"ruleId":"1770","severity":1,"message":"1809","line":964,"column":11,"nodeType":"1766","messageId":"1772","endLine":964,"endColumn":21},{"ruleId":"1773","severity":1,"message":"1774","line":6,"column":26,"nodeType":"1775","messageId":"1776","endLine":6,"endColumn":29,"suggestions":"2229"},{"ruleId":"1773","severity":1,"message":"1774","line":23,"column":38,"nodeType":"1775","messageId":"1776","endLine":23,"endColumn":41,"suggestions":"2230"},{"ruleId":"1812","severity":1,"message":"1813","line":47,"column":5,"nodeType":"1766","messageId":"1814","endLine":47,"endColumn":14},{"ruleId":"1812","severity":1,"message":"1813","line":48,"column":5,"nodeType":"1766","messageId":"1814","endLine":48,"endColumn":14},{"ruleId":"1770","severity":1,"message":"1815","line":90,"column":13,"nodeType":"1766","messageId":"1772","endLine":90,"endColumn":23},{"ruleId":"1773","severity":1,"message":"1774","line":34,"column":64,"nodeType":"1775","messageId":"1776","endLine":34,"endColumn":67,"suggestions":"2231"},{"ruleId":"1773","severity":1,"message":"1774","line":34,"column":83,"nodeType":"1775","messageId":"1776","endLine":34,"endColumn":86,"suggestions":"2232"},{"ruleId":"1773","severity":1,"message":"1774","line":52,"column":35,"nodeType":"1775","messageId":"1776","endLine":52,"endColumn":38,"suggestions":"2233"},{"ruleId":"1812","severity":1,"message":"1821","line":66,"column":3,"nodeType":"1766","messageId":"1814","endLine":66,"endColumn":6},{"ruleId":"1773","severity":1,"message":"1774","line":91,"column":67,"nodeType":"1775","messageId":"1776","endLine":91,"endColumn":70,"suggestions":"2234"},{"ruleId":"1773","severity":1,"message":"1774","line":91,"column":86,"nodeType":"1775","messageId":"1776","endLine":91,"endColumn":89,"suggestions":"2235"},{"ruleId":"1764","severity":2,"message":"1816","line":25,"column":5,"nodeType":"1766","messageId":"1767","endLine":25,"endColumn":26,"suppressions":"2236"},{"ruleId":"1764","severity":2,"message":"1819","line":44,"column":5,"nodeType":"1766","messageId":"1767","endLine":44,"endColumn":18,"suppressions":"2237"},{"ruleId":"1764","severity":2,"message":"1822","line":82,"column":5,"nodeType":"1766","messageId":"1767","endLine":82,"endColumn":29,"suppressions":"2238"},{"ruleId":"1773","severity":1,"message":"1774","line":29,"column":81,"nodeType":"1775","messageId":"1776","endLine":29,"endColumn":84,"suggestions":"2239"},{"ruleId":"1764","severity":2,"message":"1825","line":20,"column":5,"nodeType":"1766","messageId":"1767","endLine":20,"endColumn":19,"suppressions":"2240"},{"ruleId":"1773","severity":1,"message":"1774","line":85,"column":31,"nodeType":"1775","messageId":"1776","endLine":85,"endColumn":34,"suggestions":"2241"},{"ruleId":"1773","severity":1,"message":"1774","line":106,"column":37,"nodeType":"1775","messageId":"1776","endLine":106,"endColumn":40,"suggestions":"2242"},{"ruleId":"1773","severity":1,"message":"1774","line":40,"column":30,"nodeType":"1775","messageId":"1776","endLine":40,"endColumn":33,"suggestions":"2243"},{"ruleId":"1773","severity":1,"message":"1774","line":53,"column":48,"nodeType":"1775","messageId":"1776","endLine":53,"endColumn":51,"suggestions":"2244"},{"ruleId":"1773","severity":1,"message":"1774","line":110,"column":19,"nodeType":"1775","messageId":"1776","endLine":110,"endColumn":22,"suggestions":"2245"},{"ruleId":"1770","severity":1,"message":"1832","line":213,"column":11,"nodeType":"1766","messageId":"1772","endLine":213,"endColumn":34},{"ruleId":"1773","severity":1,"message":"1774","line":256,"column":31,"nodeType":"1775","messageId":"1776","endLine":256,"endColumn":34,"suggestions":"2246"},{"ruleId":"1770","severity":1,"message":"1834","line":327,"column":16,"nodeType":"1766","messageId":"1772","endLine":327,"endColumn":17},{"ruleId":"1773","severity":1,"message":"1774","line":378,"column":39,"nodeType":"1775","messageId":"1776","endLine":378,"endColumn":42,"suggestions":"2247"},{"ruleId":"1773","severity":1,"message":"1774","line":390,"column":67,"nodeType":"1775","messageId":"1776","endLine":390,"endColumn":70,"suggestions":"2248"},{"ruleId":"1773","severity":1,"message":"1774","line":452,"column":48,"nodeType":"1775","messageId":"1776","endLine":452,"endColumn":51,"suggestions":"2249"},{"ruleId":"1770","severity":1,"message":"1846","line":471,"column":11,"nodeType":"1766","messageId":"1772","endLine":471,"endColumn":19},{"ruleId":"1770","severity":1,"message":"1847","line":781,"column":35,"nodeType":"1766","messageId":"1772","endLine":781,"endColumn":43},{"ruleId":"1848","severity":1,"message":"1849","line":887,"column":43,"nodeType":"1850","messageId":"1851","endLine":887,"endColumn":108},{"ruleId":"1812","severity":1,"message":"1852","line":887,"column":50,"nodeType":"1766","messageId":"1814","endLine":887,"endColumn":56},{"ruleId":"1848","severity":1,"message":"1849","line":888,"column":43,"nodeType":"1850","messageId":"1851","endLine":888,"endColumn":84},{"ruleId":"1812","severity":1,"message":"1852","line":888,"column":50,"nodeType":"1766","messageId":"1814","endLine":888,"endColumn":56},{"ruleId":"1773","severity":1,"message":"1774","line":938,"column":62,"nodeType":"1775","messageId":"1776","endLine":938,"endColumn":65,"suggestions":"2250"},{"ruleId":"1770","severity":1,"message":"1846","line":976,"column":13,"nodeType":"1766","messageId":"1772","endLine":976,"endColumn":21},{"ruleId":"1770","severity":1,"message":"1847","line":75,"column":89,"nodeType":"1766","messageId":"1772","endLine":75,"endColumn":90},{"ruleId":"1784","severity":1,"message":"1785","line":145,"column":22,"nodeType":"1786","messageId":"1787","endLine":145,"endColumn":31},{"ruleId":"1862","severity":1,"message":"1863","line":159,"column":13,"nodeType":"1864","messageId":"1865","endLine":159,"endColumn":26},{"ruleId":"1862","severity":1,"message":"1863","line":161,"column":13,"nodeType":"1864","messageId":"1865","endLine":161,"endColumn":26},{"ruleId":"1859","severity":2,"message":"1860","line":142,"column":13,"nodeType":"1766","messageId":"1861","endLine":142,"endColumn":17,"suppressions":"2251"},{"ruleId":"1848","severity":1,"message":"1849","line":183,"column":57,"nodeType":"1850","messageId":"1851","endLine":183,"endColumn":90},{"ruleId":"1812","severity":1,"message":"1880","line":183,"column":67,"nodeType":"1766","messageId":"1814","endLine":183,"endColumn":70},{"ruleId":"1812","severity":1,"message":"1881","line":209,"column":11,"nodeType":"1766","messageId":"1814","endLine":209,"endColumn":15},{"ruleId":"1812","severity":1,"message":"1881","line":215,"column":15,"nodeType":"1766","messageId":"1814","endLine":215,"endColumn":19},{"ruleId":"1812","severity":1,"message":"1882","line":265,"column":7,"nodeType":"1766","messageId":"1814","endLine":265,"endColumn":9},{"ruleId":"1848","severity":1,"message":"1849","line":289,"column":45,"nodeType":"1850","messageId":"1851","endLine":289,"endColumn":96},{"ruleId":"1812","severity":1,"message":"1880","line":289,"column":56,"nodeType":"1766","messageId":"1814","endLine":289,"endColumn":59},{"ruleId":"1770","severity":1,"message":"1806","line":356,"column":66,"nodeType":"1766","messageId":"1772","endLine":356,"endColumn":68},{"ruleId":"1784","severity":1,"message":"1785","line":481,"column":24,"nodeType":"1786","messageId":"1787","endLine":481,"endColumn":33},{"ruleId":"1773","severity":1,"message":"1774","line":497,"column":63,"nodeType":"1775","messageId":"1776","endLine":497,"endColumn":66,"suggestions":"2252"},{"ruleId":"1773","severity":1,"message":"1774","line":500,"column":65,"nodeType":"1775","messageId":"1776","endLine":500,"endColumn":68,"suggestions":"2253"},{"ruleId":"1868","severity":2,"message":"1869","line":403,"column":9,"nodeType":"1870","messageId":"1871","endLine":403,"endColumn":75,"suppressions":"2254"},{"ruleId":"1868","severity":2,"message":"1869","line":610,"column":25,"nodeType":"1870","messageId":"1871","endLine":610,"endColumn":55,"suppressions":"2255"},{"ruleId":"1868","severity":2,"message":"1869","line":635,"column":9,"nodeType":"1870","messageId":"1871","endLine":635,"endColumn":36,"suppressions":"2256"},{"ruleId":"1784","severity":1,"message":"1785","line":132,"column":25,"nodeType":"1786","messageId":"1787","endLine":132,"endColumn":34},{"ruleId":"1784","severity":1,"message":"1785","line":141,"column":13,"nodeType":"1786","messageId":"1787","endLine":141,"endColumn":22},{"ruleId":"1770","severity":1,"message":"1888","line":169,"column":58,"nodeType":"1766","messageId":"1772","endLine":169,"endColumn":71},{"ruleId":"1812","severity":1,"message":"1889","line":178,"column":7,"nodeType":"1766","messageId":"1814","endLine":178,"endColumn":11},{"ruleId":"1812","severity":1,"message":"1889","line":182,"column":7,"nodeType":"1766","messageId":"1814","endLine":182,"endColumn":11},{"ruleId":"1812","severity":1,"message":"1889","line":196,"column":5,"nodeType":"1766","messageId":"1814","endLine":196,"endColumn":9},{"ruleId":"1770","severity":1,"message":"1890","line":215,"column":24,"nodeType":"1766","messageId":"1772","endLine":215,"endColumn":44},{"ruleId":"1770","severity":1,"message":"1891","line":215,"column":46,"nodeType":"1766","messageId":"1772","endLine":215,"endColumn":58},{"ruleId":"1770","severity":1,"message":"1888","line":215,"column":60,"nodeType":"1766","messageId":"1772","endLine":215,"endColumn":73},{"ruleId":"1770","severity":1,"message":"1890","line":251,"column":24,"nodeType":"1766","messageId":"1772","endLine":251,"endColumn":44},{"ruleId":"1770","severity":1,"message":"1891","line":251,"column":46,"nodeType":"1766","messageId":"1772","endLine":251,"endColumn":58},{"ruleId":"1770","severity":1,"message":"1888","line":251,"column":60,"nodeType":"1766","messageId":"1772","endLine":251,"endColumn":73},{"ruleId":"1885","severity":2,"message":"1886","line":129,"column":11,"nodeType":"1766","messageId":"1887","endLine":129,"endColumn":22,"suppressions":"2257"},{"ruleId":"1859","severity":2,"message":"1860","line":129,"column":11,"nodeType":"1766","messageId":"1861","endLine":129,"endColumn":22,"suppressions":"2258"},{"ruleId":"1812","severity":1,"message":"1889","line":35,"column":5,"nodeType":"1766","messageId":"1814","endLine":35,"endColumn":9},{"ruleId":"1773","severity":1,"message":"1774","line":17,"column":13,"nodeType":"1775","messageId":"1776","endLine":17,"endColumn":16,"suggestions":"2259"},{"ruleId":"1770","severity":1,"message":"1899","line":145,"column":37,"nodeType":"1766","messageId":"1772","endLine":145,"endColumn":78},{"ruleId":"1812","severity":1,"message":"1900","line":147,"column":7,"nodeType":"1766","messageId":"1901","endLine":147,"endColumn":12},{"ruleId":"1773","severity":1,"message":"1774","line":182,"column":15,"nodeType":"1775","messageId":"1776","endLine":182,"endColumn":18,"suggestions":"2260"},{"ruleId":"1773","severity":1,"message":"1774","line":245,"column":15,"nodeType":"1775","messageId":"1776","endLine":245,"endColumn":18,"suggestions":"2261"},{"ruleId":"1859","severity":2,"message":"1860","line":35,"column":11,"nodeType":"1766","messageId":"1861","endLine":35,"endColumn":15,"suppressions":"2262"},{"ruleId":"1770","severity":1,"message":"1905","line":40,"column":11,"nodeType":"1766","messageId":"1772","endLine":40,"endColumn":15},{"ruleId":"1859","severity":2,"message":"1860","line":28,"column":11,"nodeType":"1766","messageId":"1861","endLine":28,"endColumn":15,"suppressions":"2263"},{"ruleId":"1773","severity":1,"message":"1774","line":25,"column":45,"nodeType":"1775","messageId":"1776","endLine":25,"endColumn":48,"suggestions":"2264"},{"ruleId":"1773","severity":1,"message":"1774","line":27,"column":47,"nodeType":"1775","messageId":"1776","endLine":27,"endColumn":50,"suggestions":"2265"},{"ruleId":"1773","severity":1,"message":"1774","line":29,"column":45,"nodeType":"1775","messageId":"1776","endLine":29,"endColumn":48,"suggestions":"2266"},{"ruleId":"1770","severity":1,"message":"1913","line":35,"column":65,"nodeType":"1766","messageId":"1772","endLine":35,"endColumn":89},{"ruleId":"1770","severity":1,"message":"1914","line":35,"column":91,"nodeType":"1766","messageId":"1772","endLine":35,"endColumn":109},{"ruleId":"1784","severity":1,"message":"1785","line":59,"column":20,"nodeType":"1786","messageId":"1787","endLine":59,"endColumn":29},{"ruleId":"1859","severity":2,"message":"1860","line":37,"column":11,"nodeType":"1766","messageId":"1861","endLine":37,"endColumn":15,"suppressions":"2267"},{"ruleId":"1859","severity":2,"message":"1860","line":61,"column":15,"nodeType":"1766","messageId":"1861","endLine":61,"endColumn":25,"suppressions":"2268"},{"ruleId":"1770","severity":1,"message":"1915","line":50,"column":11,"nodeType":"1766","messageId":"1772","endLine":50,"endColumn":25},{"ruleId":"1773","severity":1,"message":"1774","line":65,"column":50,"nodeType":"1775","messageId":"1776","endLine":65,"endColumn":53,"suggestions":"2269"},{"ruleId":"1784","severity":1,"message":"1785","line":119,"column":28,"nodeType":"1786","messageId":"1787","endLine":119,"endColumn":37},{"ruleId":"1784","severity":1,"message":"1785","line":143,"column":22,"nodeType":"1786","messageId":"1787","endLine":143,"endColumn":31},{"ruleId":"1784","severity":1,"message":"1785","line":146,"column":26,"nodeType":"1786","messageId":"1787","endLine":146,"endColumn":35},{"ruleId":"1784","severity":1,"message":"1785","line":149,"column":25,"nodeType":"1786","messageId":"1787","endLine":149,"endColumn":34},{"ruleId":"1784","severity":1,"message":"1785","line":152,"column":24,"nodeType":"1786","messageId":"1787","endLine":152,"endColumn":33},{"ruleId":"1770","severity":1,"message":"1919","line":251,"column":55,"nodeType":"1766","messageId":"1772","endLine":251,"endColumn":61},{"ruleId":"1784","severity":1,"message":"1785","line":374,"column":15,"nodeType":"1786","messageId":"1787","endLine":374,"endColumn":24},{"ruleId":"1784","severity":1,"message":"1785","line":426,"column":54,"nodeType":"1786","messageId":"1787","endLine":426,"endColumn":63},{"ruleId":"1770","severity":1,"message":"1834","line":426,"column":64,"nodeType":"1766","messageId":"1772","endLine":426,"endColumn":65},{"ruleId":"1773","severity":1,"message":"1774","line":525,"column":50,"nodeType":"1775","messageId":"1776","endLine":525,"endColumn":53,"suggestions":"2270"},{"ruleId":"1784","severity":1,"message":"1785","line":536,"column":36,"nodeType":"1786","messageId":"1787","endLine":536,"endColumn":45},{"ruleId":"1773","severity":1,"message":"1774","line":574,"column":64,"nodeType":"1775","messageId":"1776","endLine":574,"endColumn":67,"suggestions":"2271"},{"ruleId":"1773","severity":1,"message":"1774","line":591,"column":64,"nodeType":"1775","messageId":"1776","endLine":591,"endColumn":67,"suggestions":"2272"},{"ruleId":"1773","severity":1,"message":"1774","line":772,"column":15,"nodeType":"1775","messageId":"1776","endLine":772,"endColumn":18,"suggestions":"2273"},{"ruleId":"1859","severity":2,"message":"1860","line":87,"column":11,"nodeType":"1766","messageId":"1861","endLine":87,"endColumn":15,"suppressions":"2274"},{"ruleId":"1764","severity":2,"message":"1918","line":183,"column":5,"nodeType":"1766","messageId":"1767","endLine":183,"endColumn":17,"suppressions":"2275"},{"ruleId":"1868","severity":2,"message":"1869","line":228,"column":28,"nodeType":"1870","messageId":"1871","endLine":228,"endColumn":59,"suppressions":"2276"},{"ruleId":"1868","severity":2,"message":"1869","line":240,"column":32,"nodeType":"1870","messageId":"1871","endLine":240,"endColumn":63,"suppressions":"2277"},{"ruleId":"1764","severity":2,"message":"1920","line":307,"column":23,"nodeType":"1766","messageId":"1767","endLine":307,"endColumn":43,"suppressions":"2278"},{"ruleId":"1764","severity":2,"message":"1921","line":327,"column":17,"nodeType":"1766","messageId":"1767","endLine":327,"endColumn":28,"suppressions":"2279"},{"ruleId":"1859","severity":2,"message":"1860","line":533,"column":11,"nodeType":"1766","messageId":"1861","endLine":533,"endColumn":15,"suppressions":"2280"},{"ruleId":"1770","severity":1,"message":"1919","line":69,"column":45,"nodeType":"1766","messageId":"1772","endLine":69,"endColumn":51},{"ruleId":"1770","severity":1,"message":"1932","line":81,"column":58,"nodeType":"1766","messageId":"1772","endLine":81,"endColumn":62},{"ruleId":"1770","severity":1,"message":"1933","line":81,"column":64,"nodeType":"1766","messageId":"1772","endLine":81,"endColumn":69},{"ruleId":"1773","severity":1,"message":"1774","line":87,"column":21,"nodeType":"1775","messageId":"1776","endLine":87,"endColumn":24,"suggestions":"2281"},{"ruleId":"1773","severity":1,"message":"1774","line":88,"column":33,"nodeType":"1775","messageId":"1776","endLine":88,"endColumn":36,"suggestions":"2282"},{"ruleId":"1773","severity":1,"message":"1774","line":139,"column":47,"nodeType":"1775","messageId":"1776","endLine":139,"endColumn":50,"suggestions":"2283"},{"ruleId":"1937","severity":1,"message":"1938","line":153,"column":53,"nodeType":"1939","messageId":"1940","endLine":153,"endColumn":65,"suggestions":"2284"},{"ruleId":"1773","severity":1,"message":"1774","line":26,"column":39,"nodeType":"1775","messageId":"1776","endLine":26,"endColumn":42,"suggestions":"2285"},{"ruleId":"1770","severity":1,"message":"1913","line":130,"column":26,"nodeType":"1766","messageId":"1772","endLine":130,"endColumn":50},{"ruleId":"1770","severity":1,"message":"1914","line":130,"column":52,"nodeType":"1766","messageId":"1772","endLine":130,"endColumn":70},{"ruleId":"1784","severity":1,"message":"1785","line":139,"column":62,"nodeType":"1786","messageId":"1787","endLine":139,"endColumn":71},{"ruleId":"1773","severity":1,"message":"1774","line":160,"column":47,"nodeType":"1775","messageId":"1776","endLine":160,"endColumn":50,"suggestions":"2286"},{"ruleId":"1773","severity":1,"message":"1774","line":160,"column":86,"nodeType":"1775","messageId":"1776","endLine":160,"endColumn":89,"suggestions":"2287"},{"ruleId":"1773","severity":1,"message":"1774","line":162,"column":32,"nodeType":"1775","messageId":"1776","endLine":162,"endColumn":35,"suggestions":"2288"},{"ruleId":"1773","severity":1,"message":"1774","line":164,"column":28,"nodeType":"1775","messageId":"1776","endLine":164,"endColumn":31,"suggestions":"2289"},{"ruleId":"1773","severity":1,"message":"1774","line":164,"column":67,"nodeType":"1775","messageId":"1776","endLine":164,"endColumn":70,"suggestions":"2290"},{"ruleId":"1773","severity":1,"message":"1774","line":166,"column":102,"nodeType":"1775","messageId":"1776","endLine":166,"endColumn":105,"suggestions":"2291"},{"ruleId":"1773","severity":1,"message":"1774","line":166,"column":129,"nodeType":"1775","messageId":"1776","endLine":166,"endColumn":132,"suggestions":"2292"},{"ruleId":"1773","severity":1,"message":"1774","line":188,"column":38,"nodeType":"1775","messageId":"1776","endLine":188,"endColumn":41,"suggestions":"2293"},{"ruleId":"1770","severity":1,"message":"1790","line":148,"column":47,"nodeType":"1766","messageId":"1772","endLine":148,"endColumn":52},{"ruleId":"1770","severity":1,"message":"1956","line":181,"column":45,"nodeType":"1766","messageId":"1772","endLine":181,"endColumn":63},{"ruleId":"1770","severity":1,"message":"1790","line":288,"column":46,"nodeType":"1766","messageId":"1772","endLine":288,"endColumn":51},{"ruleId":"1770","severity":1,"message":"1957","line":591,"column":11,"nodeType":"1766","messageId":"1772","endLine":591,"endColumn":18},{"ruleId":"1773","severity":1,"message":"1774","line":975,"column":40,"nodeType":"1775","messageId":"1776","endLine":975,"endColumn":43,"suggestions":"2294"},{"ruleId":"1773","severity":1,"message":"1774","line":1012,"column":39,"nodeType":"1775","messageId":"1776","endLine":1012,"endColumn":42,"suggestions":"2295"},{"ruleId":"1868","severity":2,"message":"1869","line":811,"column":25,"nodeType":"1870","messageId":"1871","endLine":811,"endColumn":82,"suppressions":"2296"},{"ruleId":"1868","severity":2,"message":"1869","line":824,"column":27,"nodeType":"1870","messageId":"1871","endLine":824,"endColumn":132,"suppressions":"2297"},{"ruleId":"1773","severity":1,"message":"1774","line":79,"column":26,"nodeType":"1775","messageId":"1776","endLine":79,"endColumn":29,"suggestions":"2298"},{"ruleId":"1770","severity":1,"message":"1964","line":230,"column":17,"nodeType":"1766","messageId":"1772","endLine":230,"endColumn":18},{"ruleId":"1812","severity":1,"message":"1965","line":418,"column":7,"nodeType":"1766","messageId":"1814","endLine":418,"endColumn":12},{"ruleId":"1770","severity":1,"message":"1966","line":566,"column":13,"nodeType":"1766","messageId":"1772","endLine":566,"endColumn":27},{"ruleId":"1784","severity":1,"message":"1785","line":677,"column":20,"nodeType":"1786","messageId":"1787","endLine":677,"endColumn":29},{"ruleId":"1784","severity":1,"message":"1785","line":684,"column":30,"nodeType":"1786","messageId":"1787","endLine":684,"endColumn":39},{"ruleId":"1784","severity":1,"message":"1785","line":690,"column":35,"nodeType":"1786","messageId":"1787","endLine":690,"endColumn":44},{"ruleId":"1784","severity":1,"message":"1785","line":695,"column":33,"nodeType":"1786","messageId":"1787","endLine":695,"endColumn":42},{"ruleId":"1784","severity":1,"message":"1785","line":749,"column":20,"nodeType":"1786","messageId":"1787","endLine":749,"endColumn":29},{"ruleId":"1770","severity":1,"message":"1790","line":806,"column":28,"nodeType":"1766","messageId":"1772","endLine":806,"endColumn":33},{"ruleId":"1784","severity":1,"message":"1785","line":865,"column":27,"nodeType":"1786","messageId":"1787","endLine":865,"endColumn":36},{"ruleId":"1770","severity":1,"message":"1967","line":875,"column":24,"nodeType":"1766","messageId":"1772","endLine":875,"endColumn":28},{"ruleId":"1770","severity":1,"message":"1968","line":875,"column":30,"nodeType":"1766","messageId":"1772","endLine":875,"endColumn":35},{"ruleId":"1859","severity":2,"message":"1860","line":674,"column":11,"nodeType":"1766","messageId":"1861","endLine":674,"endColumn":15,"suppressions":"2299"},{"ruleId":"1859","severity":2,"message":"1860","line":678,"column":15,"nodeType":"1766","messageId":"1861","endLine":678,"endColumn":22,"suppressions":"2300"},{"ruleId":"1859","severity":2,"message":"1860","line":685,"column":13,"nodeType":"1766","messageId":"1861","endLine":685,"endColumn":20,"suppressions":"2301"},{"ruleId":"1859","severity":2,"message":"1860","line":691,"column":13,"nodeType":"1766","messageId":"1861","endLine":691,"endColumn":20,"suppressions":"2302"},{"ruleId":"1859","severity":2,"message":"1860","line":746,"column":11,"nodeType":"1766","messageId":"1861","endLine":746,"endColumn":22,"suppressions":"2303"},{"ruleId":"1859","severity":2,"message":"1860","line":864,"column":13,"nodeType":"1766","messageId":"1861","endLine":864,"endColumn":17,"suppressions":"2304"},{"ruleId":"1859","severity":2,"message":"1860","line":866,"column":15,"nodeType":"1766","messageId":"1861","endLine":866,"endColumn":22,"suppressions":"2305"},{"ruleId":"1812","severity":1,"message":"2033","line":41,"column":7,"nodeType":"1766","messageId":"1814","endLine":41,"endColumn":11},{"ruleId":"1770","severity":1,"message":"2034","line":58,"column":57,"nodeType":"1766","messageId":"1772","endLine":58,"endColumn":61},{"ruleId":"1770","severity":1,"message":"1790","line":62,"column":28,"nodeType":"1766","messageId":"1772","endLine":62,"endColumn":33},{"ruleId":"1784","severity":1,"message":"1785","line":111,"column":29,"nodeType":"1786","messageId":"1787","endLine":111,"endColumn":38},{"ruleId":"1859","severity":2,"message":"1860","line":110,"column":15,"nodeType":"1766","messageId":"1861","endLine":110,"endColumn":19,"suppressions":"2306"},{"ruleId":"1859","severity":2,"message":"1860","line":112,"column":17,"nodeType":"1766","messageId":"1861","endLine":112,"endColumn":24,"suppressions":"2307"},{"ruleId":"1773","severity":1,"message":"1774","line":194,"column":26,"nodeType":"1775","messageId":"1776","endLine":194,"endColumn":29,"suggestions":"2308"},{"ruleId":"1773","severity":1,"message":"1774","line":129,"column":28,"nodeType":"1775","messageId":"1776","endLine":129,"endColumn":31,"suggestions":"2309"},{"ruleId":"1770","severity":1,"message":"2038","line":3,"column":28,"nodeType":"1766","messageId":"1772","endLine":3,"endColumn":32},{"ruleId":"1770","severity":1,"message":"1964","line":66,"column":52,"nodeType":"1766","messageId":"1772","endLine":66,"endColumn":53},{"ruleId":"1812","severity":1,"message":"2039","line":83,"column":5,"nodeType":"1766","messageId":"1901","endLine":83,"endColumn":9},{"ruleId":"1773","severity":1,"message":"1774","line":487,"column":18,"nodeType":"1775","messageId":"1776","endLine":487,"endColumn":21,"suggestions":"2310"},{"ruleId":"1773","severity":1,"message":"1774","line":811,"column":35,"nodeType":"1775","messageId":"1776","endLine":811,"endColumn":38,"suggestions":"2311"},{"ruleId":"1773","severity":1,"message":"1774","line":811,"column":88,"nodeType":"1775","messageId":"1776","endLine":811,"endColumn":91,"suggestions":"2312"},{"ruleId":"1773","severity":1,"message":"1774","line":813,"column":21,"nodeType":"1775","messageId":"1776","endLine":813,"endColumn":24,"suggestions":"2313"},{"ruleId":"1773","severity":1,"message":"1774","line":818,"column":46,"nodeType":"1775","messageId":"1776","endLine":818,"endColumn":49,"suggestions":"2314"},{"ruleId":"1773","severity":1,"message":"1774","line":830,"column":38,"nodeType":"1775","messageId":"1776","endLine":830,"endColumn":41,"suggestions":"2315"},{"ruleId":"1773","severity":1,"message":"1774","line":830,"column":92,"nodeType":"1775","messageId":"1776","endLine":830,"endColumn":95,"suggestions":"2316"},{"ruleId":"1773","severity":1,"message":"1774","line":848,"column":54,"nodeType":"1775","messageId":"1776","endLine":848,"endColumn":57,"suggestions":"2317"},{"ruleId":"1773","severity":1,"message":"1774","line":848,"column":84,"nodeType":"1775","messageId":"1776","endLine":848,"endColumn":87,"suggestions":"2318"},{"ruleId":"1929","severity":2,"message":"1930","line":61,"column":35,"nodeType":"1766","messageId":"1931","endLine":61,"endColumn":40,"suppressions":"2319"},{"ruleId":"1770","severity":1,"message":"2049","line":39,"column":44,"nodeType":"1766","messageId":"1772","endLine":39,"endColumn":52},{"ruleId":"1770","severity":1,"message":"1932","line":51,"column":58,"nodeType":"1766","messageId":"1772","endLine":51,"endColumn":62},{"ruleId":"1770","severity":1,"message":"1933","line":51,"column":64,"nodeType":"1766","messageId":"1772","endLine":51,"endColumn":69},{"ruleId":"1784","severity":1,"message":"1785","line":168,"column":20,"nodeType":"1786","messageId":"1787","endLine":168,"endColumn":29},{"ruleId":"1773","severity":1,"message":"1774","line":212,"column":35,"nodeType":"1775","messageId":"1776","endLine":212,"endColumn":38,"suggestions":"2320"},{"ruleId":"1773","severity":1,"message":"1774","line":213,"column":37,"nodeType":"1775","messageId":"1776","endLine":213,"endColumn":40,"suggestions":"2321"},{"ruleId":"1784","severity":1,"message":"1785","line":255,"column":30,"nodeType":"1786","messageId":"1787","endLine":255,"endColumn":39},{"ruleId":"1784","severity":1,"message":"1785","line":261,"column":35,"nodeType":"1786","messageId":"1787","endLine":261,"endColumn":44},{"ruleId":"1784","severity":1,"message":"1785","line":268,"column":33,"nodeType":"1786","messageId":"1787","endLine":268,"endColumn":42},{"ruleId":"1770","severity":1,"message":"1790","line":333,"column":28,"nodeType":"1766","messageId":"1772","endLine":333,"endColumn":33},{"ruleId":"1784","severity":1,"message":"1785","line":403,"column":29,"nodeType":"1786","messageId":"1787","endLine":403,"endColumn":38},{"ruleId":"1848","severity":1,"message":"1849","line":412,"column":18,"nodeType":"1850","messageId":"1851","endLine":412,"endColumn":67},{"ruleId":"1812","severity":1,"message":"2052","line":412,"column":30,"nodeType":"1766","messageId":"1814","endLine":412,"endColumn":34},{"ruleId":"1770","severity":1,"message":"1968","line":416,"column":30,"nodeType":"1766","messageId":"1772","endLine":416,"endColumn":35},{"ruleId":"1812","severity":1,"message":"1965","line":462,"column":7,"nodeType":"1766","messageId":"1814","endLine":462,"endColumn":12},{"ruleId":"1929","severity":2,"message":"1930","line":42,"column":35,"nodeType":"1766","messageId":"1931","endLine":42,"endColumn":40,"suppressions":"2322"},{"ruleId":"1859","severity":2,"message":"1860","line":165,"column":11,"nodeType":"1766","messageId":"1861","endLine":165,"endColumn":15,"suppressions":"2323"},{"ruleId":"1859","severity":2,"message":"1860","line":169,"column":15,"nodeType":"1766","messageId":"1861","endLine":169,"endColumn":22,"suppressions":"2324"},{"ruleId":"1859","severity":2,"message":"1860","line":252,"column":11,"nodeType":"1766","messageId":"1861","endLine":252,"endColumn":15,"suppressions":"2325"},{"ruleId":"1859","severity":2,"message":"1860","line":256,"column":13,"nodeType":"1766","messageId":"1861","endLine":256,"endColumn":20,"suppressions":"2326"},{"ruleId":"1859","severity":2,"message":"1860","line":262,"column":13,"nodeType":"1766","messageId":"1861","endLine":262,"endColumn":20,"suppressions":"2327"},{"ruleId":"1859","severity":2,"message":"1860","line":402,"column":15,"nodeType":"1766","messageId":"1861","endLine":402,"endColumn":19,"suppressions":"2328"},{"ruleId":"1859","severity":2,"message":"1860","line":404,"column":17,"nodeType":"1766","messageId":"1861","endLine":404,"endColumn":24,"suppressions":"2329"},{"ruleId":"1770","severity":1,"message":"2053","line":875,"column":13,"nodeType":"1766","messageId":"1772","endLine":875,"endColumn":19},{"ruleId":"1773","severity":1,"message":"1774","line":1033,"column":12,"nodeType":"1775","messageId":"1776","endLine":1033,"endColumn":15,"suggestions":"2330"},{"ruleId":"1773","severity":1,"message":"1774","line":1037,"column":9,"nodeType":"1775","messageId":"1776","endLine":1037,"endColumn":12,"suggestions":"2331"},{"ruleId":"1773","severity":1,"message":"1774","line":1039,"column":20,"nodeType":"1775","messageId":"1776","endLine":1039,"endColumn":23,"suggestions":"2332"},{"ruleId":"1773","severity":1,"message":"1774","line":1041,"column":14,"nodeType":"1775","messageId":"1776","endLine":1041,"endColumn":17,"suggestions":"2333"},{"ruleId":"1773","severity":1,"message":"1774","line":1043,"column":13,"nodeType":"1775","messageId":"1776","endLine":1043,"endColumn":16,"suggestions":"2334"},{"ruleId":"1773","severity":1,"message":"1774","line":1054,"column":41,"nodeType":"1775","messageId":"1776","endLine":1054,"endColumn":44,"suggestions":"2335"},{"ruleId":"1773","severity":1,"message":"1774","line":1055,"column":41,"nodeType":"1775","messageId":"1776","endLine":1055,"endColumn":44,"suggestions":"2336"},{"ruleId":"1773","severity":1,"message":"1774","line":1070,"column":32,"nodeType":"1775","messageId":"1776","endLine":1070,"endColumn":35,"suggestions":"2337"},{"ruleId":"1773","severity":1,"message":"1774","line":1071,"column":55,"nodeType":"1775","messageId":"1776","endLine":1071,"endColumn":58,"suggestions":"2338"},{"ruleId":"1773","severity":1,"message":"1774","line":1083,"column":30,"nodeType":"1775","messageId":"1776","endLine":1083,"endColumn":33,"suggestions":"2339"},{"ruleId":"1773","severity":1,"message":"1774","line":1084,"column":50,"nodeType":"1775","messageId":"1776","endLine":1084,"endColumn":53,"suggestions":"2340"},{"ruleId":"1770","severity":1,"message":"2071","line":1188,"column":19,"nodeType":"1766","messageId":"1772","endLine":1188,"endColumn":36},{"ruleId":"2062","severity":2,"message":"2063","line":1070,"column":36,"nodeType":"2064","messageId":"1844","endLine":1070,"endColumn":115,"suppressions":"2341"},{"ruleId":"2065","severity":2,"message":"2066","line":1070,"column":36,"nodeType":"2064","messageId":"2067","endLine":1070,"endColumn":115,"suppressions":"2342"},{"ruleId":"2062","severity":2,"message":"2063","line":1083,"column":34,"nodeType":"2064","messageId":"1844","endLine":1083,"endColumn":102,"suppressions":"2343"},{"ruleId":"2065","severity":2,"message":"2066","line":1083,"column":34,"nodeType":"2064","messageId":"2067","endLine":1083,"endColumn":102,"suppressions":"2344"},{"ruleId":"1950","severity":2,"message":"1951","line":1086,"column":32,"nodeType":"1952","messageId":"1953","endLine":1086,"endColumn":41,"suppressions":"2345"},{"ruleId":"1770","severity":1,"message":"2072","line":1,"column":31,"nodeType":"1766","messageId":"1772","endLine":1,"endColumn":40},{"ruleId":"1770","severity":1,"message":"2072","line":1,"column":31,"nodeType":"1766","messageId":"1772","endLine":1,"endColumn":40},{"ruleId":"1812","severity":1,"message":"2073","line":30,"column":5,"nodeType":"1766","messageId":"1814","endLine":30,"endColumn":11},{"ruleId":"1773","severity":1,"message":"1774","line":12,"column":22,"nodeType":"1775","messageId":"1776","endLine":12,"endColumn":25,"suggestions":"2346"},{"ruleId":"1773","severity":1,"message":"1774","line":41,"column":53,"nodeType":"1775","messageId":"1776","endLine":41,"endColumn":56,"suggestions":"2347"},{"ruleId":"1773","severity":1,"message":"1774","line":47,"column":56,"nodeType":"1775","messageId":"1776","endLine":47,"endColumn":59,"suggestions":"2348"},{"ruleId":"1770","severity":1,"message":"2080","line":167,"column":13,"nodeType":"1766","messageId":"1772","endLine":167,"endColumn":21},{"ruleId":"1784","severity":1,"message":"2081","line":262,"column":20,"nodeType":"1786","messageId":"1787","endLine":262,"endColumn":35},{"ruleId":"1770","severity":1,"message":"2083","line":288,"column":13,"nodeType":"1766","messageId":"1772","endLine":288,"endColumn":20},{"ruleId":"1812","severity":1,"message":"2084","line":293,"column":5,"nodeType":"1766","messageId":"1814","endLine":293,"endColumn":15},{"ruleId":"1773","severity":1,"message":"1774","line":301,"column":46,"nodeType":"1775","messageId":"1776","endLine":301,"endColumn":49,"suggestions":"2349"},{"ruleId":"1773","severity":1,"message":"1774","line":302,"column":26,"nodeType":"1775","messageId":"1776","endLine":302,"endColumn":29,"suggestions":"2350"},{"ruleId":"1773","severity":1,"message":"1774","line":313,"column":41,"nodeType":"1775","messageId":"1776","endLine":313,"endColumn":44,"suggestions":"2351"},{"ruleId":"1773","severity":1,"message":"1774","line":497,"column":84,"nodeType":"1775","messageId":"1776","endLine":497,"endColumn":87,"suggestions":"2352"},{"ruleId":"1770","severity":1,"message":"1790","line":522,"column":38,"nodeType":"1766","messageId":"1772","endLine":522,"endColumn":43},{"ruleId":"1770","severity":1,"message":"1790","line":530,"column":38,"nodeType":"1766","messageId":"1772","endLine":530,"endColumn":43},{"ruleId":"1770","severity":1,"message":"1790","line":537,"column":38,"nodeType":"1766","messageId":"1772","endLine":537,"endColumn":43},{"ruleId":"1859","severity":2,"message":"1860","line":251,"column":11,"nodeType":"1766","messageId":"1861","endLine":251,"endColumn":15,"suppressions":"2353"},{"ruleId":"1848","severity":1,"message":"1849","line":23,"column":58,"nodeType":"1850","messageId":"1851","endLine":23,"endColumn":89},{"ruleId":"1812","severity":1,"message":"1880","line":23,"column":68,"nodeType":"1766","messageId":"1814","endLine":23,"endColumn":71},{"ruleId":"1848","severity":1,"message":"1849","line":48,"column":28,"nodeType":"1850","messageId":"1851","endLine":48,"endColumn":59},{"ruleId":"1812","severity":1,"message":"1880","line":48,"column":38,"nodeType":"1766","messageId":"1814","endLine":48,"endColumn":41},{"ruleId":"1848","severity":1,"message":"1849","line":77,"column":30,"nodeType":"1850","messageId":"1851","endLine":77,"endColumn":60},{"ruleId":"1812","severity":1,"message":"1880","line":77,"column":40,"nodeType":"1766","messageId":"1814","endLine":77,"endColumn":43},{"ruleId":"1773","severity":1,"message":"1774","line":102,"column":18,"nodeType":"1775","messageId":"1776","endLine":102,"endColumn":21,"suggestions":"2354"},{"ruleId":"1773","severity":1,"message":"1774","line":230,"column":38,"nodeType":"1775","messageId":"1776","endLine":230,"endColumn":41,"suggestions":"2355"},{"ruleId":"1773","severity":1,"message":"1774","line":252,"column":29,"nodeType":"1775","messageId":"1776","endLine":252,"endColumn":32,"suggestions":"2356"},{"ruleId":"1773","severity":1,"message":"1774","line":273,"column":29,"nodeType":"1775","messageId":"1776","endLine":273,"endColumn":32,"suggestions":"2357"},{"ruleId":"1773","severity":1,"message":"1774","line":64,"column":72,"nodeType":"1775","messageId":"1776","endLine":64,"endColumn":75,"suggestions":"2358"},{"ruleId":"1812","severity":1,"message":"2094","line":71,"column":9,"nodeType":"1766","messageId":"1901","endLine":71,"endColumn":15},{"ruleId":"1812","severity":1,"message":"2094","line":74,"column":9,"nodeType":"1766","messageId":"1901","endLine":74,"endColumn":15},{"ruleId":"1812","severity":1,"message":"2094","line":81,"column":9,"nodeType":"1766","messageId":"1901","endLine":81,"endColumn":15},{"ruleId":"1812","severity":1,"message":"2094","line":84,"column":9,"nodeType":"1766","messageId":"1901","endLine":84,"endColumn":15},{"ruleId":"1812","severity":1,"message":"2095","line":101,"column":5,"nodeType":"1766","messageId":"1814","endLine":101,"endColumn":11},{"ruleId":"1812","severity":1,"message":"2095","line":224,"column":10,"nodeType":"1766","messageId":"1814","endLine":224,"endColumn":16},{"ruleId":"1812","severity":1,"message":"2095","line":241,"column":10,"nodeType":"1766","messageId":"1814","endLine":241,"endColumn":16},{"ruleId":"1812","severity":1,"message":"2095","line":250,"column":10,"nodeType":"1766","messageId":"1814","endLine":250,"endColumn":16},{"ruleId":"1812","severity":1,"message":"2095","line":410,"column":3,"nodeType":"1766","messageId":"1814","endLine":410,"endColumn":9},{"ruleId":"1937","severity":1,"message":"1938","line":57,"column":35,"nodeType":"1939","messageId":"1940","endLine":57,"endColumn":54},{"ruleId":"1937","severity":1,"message":"1938","line":90,"column":35,"nodeType":"1939","messageId":"1940","endLine":90,"endColumn":54},{"ruleId":"1937","severity":1,"message":"1938","line":125,"column":33,"nodeType":"1939","messageId":"1940","endLine":125,"endColumn":52},{"ruleId":"1937","severity":1,"message":"1938","line":126,"column":75,"nodeType":"1939","messageId":"1940","endLine":126,"endColumn":94},{"ruleId":"1937","severity":1,"message":"1938","line":128,"column":53,"nodeType":"1939","messageId":"1940","endLine":128,"endColumn":72},{"ruleId":"1937","severity":1,"message":"1938","line":190,"column":33,"nodeType":"1939","messageId":"1940","endLine":190,"endColumn":52},{"ruleId":"1773","severity":1,"message":"1774","line":51,"column":18,"nodeType":"1775","messageId":"1776","endLine":51,"endColumn":21,"suggestions":"2359"},{"ruleId":"1773","severity":1,"message":"1774","line":176,"column":57,"nodeType":"1775","messageId":"1776","endLine":176,"endColumn":60,"suggestions":"2360"},{"ruleId":"1773","severity":1,"message":"1774","line":247,"column":40,"nodeType":"1775","messageId":"1776","endLine":247,"endColumn":43,"suggestions":"2361"},{"ruleId":"1773","severity":1,"message":"1774","line":536,"column":13,"nodeType":"1775","messageId":"1776","endLine":536,"endColumn":16,"suggestions":"2362"},{"ruleId":"1773","severity":1,"message":"1774","line":540,"column":29,"nodeType":"1775","messageId":"1776","endLine":540,"endColumn":32,"suggestions":"2363"},{"ruleId":"1773","severity":1,"message":"1774","line":580,"column":53,"nodeType":"1775","messageId":"1776","endLine":580,"endColumn":56,"suggestions":"2364"},{"ruleId":"1773","severity":1,"message":"1774","line":580,"column":76,"nodeType":"1775","messageId":"1776","endLine":580,"endColumn":79,"suggestions":"2365"},{"ruleId":"1770","severity":1,"message":"1899","line":58,"column":37,"nodeType":"1766","messageId":"1772","endLine":58,"endColumn":58},{"ruleId":"1770","severity":1,"message":"1899","line":63,"column":25,"nodeType":"1766","messageId":"1772","endLine":63,"endColumn":46},{"ruleId":"1770","severity":1,"message":"2117","line":63,"column":48,"nodeType":"1766","messageId":"1772","endLine":63,"endColumn":61},{"ruleId":"1770","severity":1,"message":"1899","line":90,"column":32,"nodeType":"1766","messageId":"1772","endLine":90,"endColumn":53},{"ruleId":"1770","severity":1,"message":"1899","line":153,"column":37,"nodeType":"1766","messageId":"1772","endLine":153,"endColumn":58},{"ruleId":"1770","severity":1,"message":"2119","line":269,"column":11,"nodeType":"1766","messageId":"1772","endLine":269,"endColumn":20},{"ruleId":"1770","severity":1,"message":"2120","line":270,"column":11,"nodeType":"1766","messageId":"1772","endLine":270,"endColumn":23},{"ruleId":"1812","severity":1,"message":"2121","line":358,"column":9,"nodeType":"1766","messageId":"1901","endLine":358,"endColumn":16},{"ruleId":"1812","severity":1,"message":"2122","line":359,"column":9,"nodeType":"1766","messageId":"1814","endLine":359,"endColumn":16},{"ruleId":"1812","severity":1,"message":"2121","line":361,"column":9,"nodeType":"1766","messageId":"1901","endLine":361,"endColumn":16},{"ruleId":"1770","severity":1,"message":"1899","line":373,"column":31,"nodeType":"1766","messageId":"1772","endLine":373,"endColumn":52},{"ruleId":"1770","severity":1,"message":"2117","line":373,"column":54,"nodeType":"1766","messageId":"1772","endLine":373,"endColumn":67},{"ruleId":"1770","severity":1,"message":"1899","line":415,"column":37,"nodeType":"1766","messageId":"1772","endLine":415,"endColumn":58},{"ruleId":"1770","severity":1,"message":"1899","line":431,"column":31,"nodeType":"1766","messageId":"1772","endLine":431,"endColumn":52},{"ruleId":"1770","severity":1,"message":"2117","line":431,"column":54,"nodeType":"1766","messageId":"1772","endLine":431,"endColumn":67},{"ruleId":"1773","severity":1,"message":"1774","line":448,"column":46,"nodeType":"1775","messageId":"1776","endLine":448,"endColumn":49,"suggestions":"2366"},{"ruleId":"1868","severity":2,"message":"1869","line":477,"column":17,"nodeType":"1870","messageId":"1871","endLine":477,"endColumn":74,"suppressions":"2367"},{"ruleId":"1773","severity":1,"message":"1774","line":20,"column":20,"nodeType":"1775","messageId":"1776","endLine":20,"endColumn":23,"suggestions":"2368"},{"ruleId":"1773","severity":1,"message":"1774","line":49,"column":18,"nodeType":"1775","messageId":"1776","endLine":49,"endColumn":21,"suggestions":"2369"},{"ruleId":"1770","severity":1,"message":"2128","line":102,"column":13,"nodeType":"1766","messageId":"1772","endLine":102,"endColumn":35},{"ruleId":"1770","severity":1,"message":"1899","line":179,"column":37,"nodeType":"1766","messageId":"1772","endLine":179,"endColumn":58},{"ruleId":"1812","severity":1,"message":"2129","line":218,"column":11,"nodeType":"1766","messageId":"1814","endLine":218,"endColumn":14},{"ruleId":"1770","severity":1,"message":"1899","line":256,"column":31,"nodeType":"1766","messageId":"1772","endLine":256,"endColumn":52},{"ruleId":"1770","severity":1,"message":"2117","line":256,"column":54,"nodeType":"1766","messageId":"1772","endLine":256,"endColumn":67},{"ruleId":"1812","severity":1,"message":"1881","line":303,"column":9,"nodeType":"1766","messageId":"1814","endLine":303,"endColumn":13},{"ruleId":"1770","severity":1,"message":"2130","line":313,"column":5,"nodeType":"1766","messageId":"1772","endLine":313,"endColumn":28},{"ruleId":"1770","severity":1,"message":"2131","line":314,"column":5,"nodeType":"1766","messageId":"1772","endLine":314,"endColumn":122},{"ruleId":"1770","severity":1,"message":"2132","line":319,"column":12,"nodeType":"1766","messageId":"1772","endLine":319,"endColumn":30},{"ruleId":"1770","severity":1,"message":"1899","line":319,"column":32,"nodeType":"1766","messageId":"1772","endLine":319,"endColumn":53},{"ruleId":"1784","severity":1,"message":"1785","line":8,"column":16,"nodeType":"2102","messageId":"1787","endLine":8,"endColumn":25},{"ruleId":"1770","severity":1,"message":"2169","line":18,"column":12,"nodeType":"1766","messageId":"1772","endLine":18,"endColumn":28},{"ruleId":"1773","severity":1,"message":"1774","line":18,"column":89,"nodeType":"1775","messageId":"1776","endLine":18,"endColumn":92,"suggestions":"2370"},{"ruleId":"1773","severity":1,"message":"1774","line":34,"column":42,"nodeType":"1775","messageId":"1776","endLine":34,"endColumn":45,"suggestions":"2371"},{"ruleId":"1773","severity":1,"message":"1774","line":37,"column":22,"nodeType":"1775","messageId":"1776","endLine":37,"endColumn":25,"suggestions":"2372"},{"ruleId":"1773","severity":1,"message":"1774","line":38,"column":16,"nodeType":"1775","messageId":"1776","endLine":38,"endColumn":19,"suggestions":"2373"},{"ruleId":"1773","severity":1,"message":"1774","line":41,"column":23,"nodeType":"1775","messageId":"1776","endLine":41,"endColumn":26,"suggestions":"2374"},{"ruleId":"1773","severity":1,"message":"1774","line":41,"column":40,"nodeType":"1775","messageId":"1776","endLine":41,"endColumn":43,"suggestions":"2375"},{"ruleId":"1773","severity":1,"message":"1774","line":41,"column":52,"nodeType":"1775","messageId":"1776","endLine":41,"endColumn":55,"suggestions":"2376"},{"ruleId":"1773","severity":1,"message":"1774","line":45,"column":49,"nodeType":"1775","messageId":"1776","endLine":45,"endColumn":52,"suggestions":"2377"},{"ruleId":"1773","severity":1,"message":"1774","line":45,"column":78,"nodeType":"1775","messageId":"1776","endLine":45,"endColumn":81,"suggestions":"2378"},{"ruleId":"1773","severity":1,"message":"1774","line":47,"column":24,"nodeType":"1775","messageId":"1776","endLine":47,"endColumn":27,"suggestions":"2379"},{"ruleId":"1773","severity":1,"message":"1774","line":140,"column":59,"nodeType":"1775","messageId":"1776","endLine":140,"endColumn":62,"suggestions":"2380"},{"ruleId":"1773","severity":1,"message":"1774","line":151,"column":62,"nodeType":"1775","messageId":"1776","endLine":151,"endColumn":65,"suggestions":"2381"},{"ruleId":"1770","severity":1,"message":"2185","line":15,"column":9,"nodeType":"1766","messageId":"1772","endLine":15,"endColumn":18},{"ruleId":"1773","severity":1,"message":"1774","line":45,"column":54,"nodeType":"1775","messageId":"1776","endLine":45,"endColumn":57,"suggestions":"2382"},{"ruleId":"1770","severity":1,"message":"2187","line":97,"column":11,"nodeType":"1766","messageId":"1772","endLine":97,"endColumn":16},{"ruleId":"2188","severity":1,"message":"2189","line":195,"column":19,"nodeType":"2064","messageId":"2190","endLine":195,"endColumn":33},{"ruleId":"2188","severity":1,"message":"2189","line":205,"column":21,"nodeType":"2064","messageId":"2190","endLine":205,"endColumn":35},{"ruleId":"2188","severity":1,"message":"2189","line":303,"column":19,"nodeType":"2064","messageId":"2190","endLine":303,"endColumn":33},{"ruleId":"2188","severity":1,"message":"2189","line":313,"column":23,"nodeType":"2064","messageId":"2190","endLine":313,"endColumn":37},"@typescript-eslint/no-use-before-define","'combineLabelsForDB' was used before it was defined.","Identifier","noUseBeforeDefine","'cohortCreationDBHandler' was used before it was defined.","'Cohort' was used before it was defined.","@typescript-eslint/no-unused-vars","'test' is assigned a value but never used.","unusedVar","@typescript-eslint/no-explicit-any","Unexpected any. Specify a different type.","TSAnyKeyword","unexpectedAny",["2383","2384"],"'IBloodlineElement' is defined but never used.",["2385","2386"],"'height' is defined but never used.","'width' is defined but never used.",["2387","2388"],["2389","2390"],"func-names","Unexpected unnamed function.","FunctionExpression","unnamed",["2391","2392"],["2393","2394"],"'event' is defined but never used.",["2395","2396"],["2397","2398"],["2399","2400"],["2401","2402"],"@typescript-eslint/no-shadow","'i' is already declared in the upper scope on line 493 column 16.","noShadow","'summaries' is assigned a value but never used.","'currChtInfo' is already declared in the upper scope on line 571 column 13.","'chtName' is already declared in the upper scope on line 572 column 13.","'chtValues' is already declared in the upper scope on line 576 column 13.",["2403","2404"],"'tip' is already declared in the upper scope on line 18 column 9.","'setOnboardingCookie' was used before it was defined.",["2405","2406"],"'ev' is defined but never used.","'viewDescr' is defined but never used.","'barHeight' is assigned a value but never used.","'scrollLink' is assigned a value but never used.",["2407","2408"],["2409","2410"],"no-param-reassign","Assignment to property of function parameter 'container'.","assignmentToFunctionParamProp","'currMaxRow' is assigned a value but never used.","'addOverviewCohortImpl' was used before it was defined.",["2411","2412"],["2413","2414"],"'setChtCounter' was used before it was defined.",["2415","2416"],"Assignment to property of function parameter 'app'.","'removeOverviewCohortImpl' was used before it was defined.",["2417","2418"],["2419","2420"],"'setDatasetImpl' was used before it was defined.",["2421","2422"],["2423","2424"],["2425","2426"],["2427","2428"],["2429","2430"],["2431","2432"],"'badgeIds' is assigned a value but never used.",["2433","2434"],"'d' is defined but never used.",["2435","2436"],["2437","2438"],"default-case","Expected a default case.","SwitchStatement","missingDefaultCase","no-case-declarations","Unexpected lexical declaration in case block.","VariableDeclaration","unexpected",["2439","2440"],"'optionId' is assigned a value but never used.","'e' is defined but never used.","no-return-assign","Arrow function should not return assignment.","ArrowFunctionExpression","arrowAssignment","Assignment to property of function parameter 'parent'.","'d' is already declared in the upper scope on line 912 column 14.",["2441","2442"],"no-useless-concat","Unexpected string concatenation of literals.","BinaryExpression","unexpectedConcat","@typescript-eslint/no-this-alias","Unexpected aliasing of 'this' to local variable.","thisAssignment","@typescript-eslint/ban-ts-comment","Do not use \"@ts-ignore\" because it alters compilation errors.","Line","tsDirectiveComment","'TaskviewInput' was used before it was defined.","'TaskviewOutput' was used before it was defined.","no-await-in-loop","Unexpected `await` inside a loop.","AwaitExpression","unexpectedAwait",["2443","2444"],["2445","2446"],"@typescript-eslint/no-loop-func","Function declared in a loop contains unsafe references to variable(s) 'getLoaderCohort'.","unsafeRefs","array-callback-return","Array.prototype.map() expects a return value from arrow function.","expectedInside","Assignment to property of function parameter 'cht'.","Assignment to property of function parameter 'elem'.","Assignment to property of function parameter 'ev'.","import/named","taskview not found in '../../cohortview'","@typescript-eslint/naming-convention","Variable name `_thisColumn` must match one of the following formats: camelCase, PascalCase, UPPER_CASE","doesNotMatchFormat","'index' is defined but never used.","Assignment to property of function parameter 'cell'.","'cell' is defined but never used.","'cht' is defined but never used.","'taskview' is already declared in the upper scope on line 8 column 10.","'Histogram' was used before it was defined.",["2447","2448"],"no-lonely-if","Unexpected if as the only statement in an else block.","IfStatement","unexpectedLonelyIf","'filters' is defined but never used.","Assignment to function parameter 'value'.","assignmentToFunctionParam",["2449","2450"],["2451","2452"],"'PrevalenceBar' was used before it was defined.","'spec' is assigned a value but never used.","import/export","No named exports found in module './SearchColumn'.","Literal","No named exports found in module './Taskview'.",["2453","2454"],["2455","2456"],["2457","2458"],"'attributes' is defined but never used.","'cohorts' is defined but never used.","'tableContainer' is assigned a value but never used.",["2459","2460"],"'timestamp' is already declared in the upper scope on line 76 column 11.","'insertLegend' was used before it was defined.","'reject' is defined but never used.","'textColor4Background' was used before it was defined.","'score2color' was used before it was defined.","no-restricted-globals","Unexpected use of 'isNaN'. Use Number.isNaN instead https://github.com/airbnb/javascript#standard-library--isnan","customMessage",["2461","2462"],["2463","2464"],["2465","2466"],["2467","2468"],"no-async-promise-executor","Promise executor functions should not be async.","async","'data' is defined but never used.","'label' is defined but never used.",["2469","2470"],["2471","2472"],["2473","2474"],"@typescript-eslint/no-non-null-assertion","Forbidden non-null assertion.","TSNonNullExpression","noNonNull",["2475"],["2476","2477"],["2478","2479"],["2480","2481"],["2482","2483"],["2484","2485"],["2486","2487"],["2488","2489"],["2490","2491"],"new-cap","A constructor name should not start with a lowercase letter.","NewExpression","lower",["2492","2493"],"getRootCohort not found in '../../cohortview'","'exclState' is defined but never used.","'taskRep' is assigned a value but never used.",["2494","2495"],["2496","2497"],"@typescript-eslint/ban-types","Don't use `Object` as a type. The `Object` type actually means \"any non-nullish value\", so it is marginally better than `unknown`.\n- If you want a type meaning \"any object\", you probably want `object` instead.\n- If you want a type meaning \"any value\", you probably want `unknown` instead.","bannedTypeMessage",["2498","2499"],"'i' is defined but never used.","Assignment to property of function parameter 'chart'.","'closingBracket' is assigned a value but never used.","'name' is defined but never used.","'value' is defined but never used.","prettier/prettier","Replace `IdValuePair` with `·IdValuePair·`","replace",{"range":"2500","text":"2501"},"no-useless-escape","Unnecessary escape character: \\'.","TemplateElement","unnecessaryEscape",["2502","2503"],["2504","2505"],["2506","2507"],["2508","2509"],["2510","2511"],["2512","2513"],["2514","2515"],["2516","2517"],["2518","2519"],["2520","2521"],["2522","2523"],["2524","2525"],["2526","2527"],["2528","2529"],["2530","2531"],["2532","2533"],["2534","2535"],["2536","2537"],["2538","2539"],["2540","2541"],["2542","2543"],["2544","2545"],["2546","2547"],["2548","2549"],["2550","2551"],["2552","2553"],["2554","2555"],["2556","2557"],["2558","2559"],["2560","2561"],["2562","2563"],["2564","2565"],["2566","2567"],["2568","2569"],["2570","2571"],["2572","2573"],["2574","2575"],["2576","2577"],["2578","2579"],["2580","2581"],["2582","2583"],["2584","2585"],["2586","2587"],["2588","2589"],["2590","2591"],["2592","2593"],["2594","2595"],["2596","2597"],["2598","2599"],["2600","2601"],["2602","2603"],["2604","2605"],["2606","2607"],["2608","2609"],["2610","2611"],["2612","2613"],"Assignment to property of function parameter 'spec'.","'axis' is defined but never used.",["2614","2615"],"IdValuePair not found in '../../data/Attribute'",["2616","2617"],"'None' is defined but never used.","Assignment to function parameter 'data'.",["2618","2619"],["2620","2621"],["2622","2623"],["2624","2625"],["2626","2627"],["2628","2629"],["2630","2631"],["2632","2633"],["2634","2635"],"'chtIndex' is defined but never used.",["2636","2637"],["2638","2639"],"Assignment to property of function parameter 'node'.","'filter' is assigned a value but never used.",["2640","2641"],["2642","2643"],["2644","2645"],["2646","2647"],["2648","2649"],["2650","2651"],["2652","2653"],["2654","2655"],"global-require","Unexpected require().","CallExpression","@typescript-eslint/no-var-requires","Require statement not part of import statement.","noVarReqs",["2656","2657"],["2658","2659"],["2660","2661"],"'attribute' is defined but never used.","'VisConfig' is defined but never used.","Assignment to property of function parameter 'option'.",["2662","2663"],"no-self-compare","Comparing to itself is potentially pointless.","comparingToSelf",["2664","2665"],["2666","2667"],"'dataBtns' is assigned a value but never used.","Unexpected unnamed async function.","'dataSourcesAndPanels' is already declared in the upper scope on line 187 column 11.","'loading' is assigned a value but never used.","Assignment to property of function parameter 'newDataset'.",["2668","2669"],["2670","2671"],["2672","2673"],["2674","2675"],["2676","2677"],["2678","2679"],["2680","2681"],["2682","2683"],["2684","2685"],"Assignment to function parameter 'values'.","Assignment to property of function parameter 'params'.","Delete `⏎`","delete",{"range":"2686","text":"2687"},["2688","2689"],"consistent-return","Expected to return a value at the end of function 'chooseDataSource'.","FunctionDeclaration","missingReturn",["2690","2691"],"'toLineUpCategories' was used before it was defined.",["2692","2693"],"'resolveDataTypes' was used before it was defined.","'d' is already declared in the upper scope on line 238 column 39.","'d' is already declared in the upper scope on line 323 column 41.","'d' is already declared in the upper scope on line 408 column 25.",["2694","2695"],["2696","2697"],"'addEmptyOption' was used before it was defined.","'selectCategoricalColumn' was used before it was defined.",["2698","2699"],["2700","2701"],"'bins' is defined but never used.","'subType2Type' was used before it was defined.","'scoreView' is assigned a value but never used.","'scoreFilters' is assigned a value but never used.","Assignment to function parameter 'filters'.","Assignment to property of function parameter 'filters'.",["2702","2703"],"'multiAttributeFilter' was used before it was defined.",["2704","2705"],["2706","2707"],"getRootCohort not found in '../cohortview'","'tempAgents' is assigned a value but never used.","Assignment to property of function parameter 'row'.","'histType' is defined but never used.","'params' is defined but never used.","'cohortDbId' is defined but never used.","Expected to return a value at the end of method 'filter'.","Don't use `Function` as a type. The `Function` type accepts any function-like value.\nIt provides no type safety when calling the function, which can be a common source of bugs.\nIt also accepts things like class declarations, which will throw at runtime as they will not be called with `new`.\nIf you are expecting the function to accept certain arguments, you should explicitly define the function shape.","Multiple exports of name 'CoralApp'.","ExportAllDeclaration","Multiple exports of name 'Coral'.","Multiple exports of name 'CohortSelectionListener'.","Multiple exports of name 'ECloneFilterTypes'.","Multiple exports of name 'ICohortClassBasicValues'.","Multiple exports of name 'ICohortClassDatabaseValues'.","Multiple exports of name 'IPanelDesc'.","Multiple exports of name 'IDatasetDesc'.","Multiple exports of name 'TaskType'.","Multiple exports of name 'EElementProvType'.","Multiple exports of name 'IProvAttrAndValuesCohort'.","Multiple exports of name 'IProvAttrAndValuesTask'.","Multiple exports of name 'IElementProvJSON'.","Multiple exports of name 'IElementProvJSONCohort'.","Multiple exports of name 'IElementProvJSONTask'.","Multiple exports of name 'IElement'.","Multiple exports of name 'IBloodlineElement'.","Multiple exports of name 'ICohort'.","Multiple exports of name 'IInputCohort'.","Multiple exports of name 'IOutputCohort'.","Multiple exports of name 'ITask'.","Multiple exports of name 'IOverviewLayout'.","Multiple exports of name 'IRectLayout'.","Multiple exports of name 'ICohortRep'.","Multiple exports of name 'IRectCohortRep'.","Multiple exports of name 'ITaskRep'.","Multiple exports of name 'IRectTaskRep'.","Multiple exports of name 'ISetTwoLabelFunc'.","Multiple exports of name 'ISetLabelFunc'.","Multiple exports of name 'ITaskParams'.",["2708","2709"],"Don't use `{}` as a type. `{}` actually means \"any non-nullish value\".\n- If you want a type meaning \"any object\", you probably want `object` instead.\n- If you want a type meaning \"any value\", you probably want `unknown` instead.\n- If you want a type meaning \"empty object\", you probably want `Record` instead.","TSTypeLiteral","'actionCompressor' is defined but never used.",["2710","2711"],["2712","2713"],["2714","2715"],["2716","2717"],["2718","2719"],["2720","2721"],["2722","2723"],["2724","2725"],["2726","2727"],["2728","2729"],["2730","2731"],["2732","2733"],"no-promise-executor-return","Return values from promise executor functions cannot be read.","returnsValue","'attribute' is assigned a value but never used.",["2734","2735"],"'opOne' is assigned a value but never used.","no-prototype-builtins","Do not access Object.prototype method 'hasOwnProperty' from target object.","prototypeBuildIn",["2736","2737"],["2738"],["2739"],["2740"],["2741"],["2742"],["2743"],["2744"],["2745"],["2746"],["2747"],["2748"],["2749"],["2750"],["2751"],["2752"],["2753"],["2754"],["2755"],["2756"],["2757"],["2758"],["2759"],["2760"],["2761"],["2762"],["2763","2764"],["2765","2766"],["2767","2768"],["2769","2770"],["2771","2772"],["2773","2774"],["2775","2776"],["2777","2778"],["2779","2780"],["2781","2782"],["2783"],["2784","2785"],["2786","2787"],["2788","2789"],["2790","2791"],["2792","2793"],["2794","2795"],["2796","2797"],["2798","2799"],["2800"],["2801"],["2802"],["2803","2804"],["2805"],["2806","2807"],["2808","2809"],["2810","2811"],["2812","2813"],["2814","2815"],["2816","2817"],["2818","2819"],["2820","2821"],["2822","2823"],["2824","2825"],["2826"],["2827","2828"],["2829","2830"],["2831"],["2832"],["2833"],["2834"],["2835"],["2836","2837"],["2838","2839"],["2840","2841"],["2842"],["2843"],["2844","2845"],["2846","2847"],["2848","2849"],["2850"],["2851"],["2852","2853"],["2854","2855"],["2856","2857"],["2858","2859"],["2860","2861"],["2862"],["2863"],["2864"],["2865"],["2866"],["2867","2868"],["2869"],["2870","2871"],["2872","2873"],["2874","2875"],["2876"],["2877","2878"],["2879","2880"],["2881","2882"],["2883","2884"],["2885","2886"],["2887","2888"],["2889","2890"],["2891","2892"],["2893","2894"],["2895","2896"],["2897","2898"],["2899"],["2900"],["2901","2902"],["2903"],["2904"],["2905"],["2906"],["2907"],["2908"],["2909"],["2910"],["2911"],["2912","2913"],["2914","2915"],["2916","2917"],["2918","2919"],["2920","2921"],["2922","2923"],["2924","2925"],["2926","2927"],["2928","2929"],["2930","2931"],["2932","2933"],["2934"],["2935","2936"],["2937","2938"],["2939"],["2940"],["2941"],["2942"],["2943"],["2944"],["2945"],["2946"],["2947","2948"],["2949","2950"],["2951","2952"],["2953","2954"],["2955","2956"],["2957","2958"],["2959","2960"],["2961","2962"],["2963","2964"],["2965","2966"],["2967","2968"],["2969"],["2970"],["2971"],["2972"],["2973"],["2974","2975"],["2976","2977"],["2978","2979"],["2980","2981"],["2982","2983"],["2984","2985"],["2986","2987"],["2988"],["2989","2990"],["2991","2992"],["2993","2994"],["2995","2996"],["2997","2998"],["2999","3000"],["3001","3002"],["3003","3004"],["3005","3006"],["3007","3008"],["3009","3010"],["3011","3012"],["3013","3014"],["3015"],["3016","3017"],["3018","3019"],["3020","3021"],["3022","3023"],["3024","3025"],["3026","3027"],["3028","3029"],["3030","3031"],["3032","3033"],["3034","3035"],["3036","3037"],["3038","3039"],["3040","3041"],["3042","3043"],["3044","3045"],{"messageId":"3046","fix":"3047","desc":"3048"},{"messageId":"3049","fix":"3050","desc":"3051"},{"messageId":"3046","fix":"3052","desc":"3048"},{"messageId":"3049","fix":"3053","desc":"3051"},{"messageId":"3046","fix":"3054","desc":"3048"},{"messageId":"3049","fix":"3055","desc":"3051"},{"messageId":"3046","fix":"3056","desc":"3048"},{"messageId":"3049","fix":"3057","desc":"3051"},{"messageId":"3046","fix":"3058","desc":"3048"},{"messageId":"3049","fix":"3059","desc":"3051"},{"messageId":"3046","fix":"3060","desc":"3048"},{"messageId":"3049","fix":"3061","desc":"3051"},{"messageId":"3046","fix":"3062","desc":"3048"},{"messageId":"3049","fix":"3063","desc":"3051"},{"messageId":"3046","fix":"3064","desc":"3048"},{"messageId":"3049","fix":"3065","desc":"3051"},{"messageId":"3046","fix":"3066","desc":"3048"},{"messageId":"3049","fix":"3067","desc":"3051"},{"messageId":"3046","fix":"3068","desc":"3048"},{"messageId":"3049","fix":"3069","desc":"3051"},{"messageId":"3046","fix":"3070","desc":"3048"},{"messageId":"3049","fix":"3071","desc":"3051"},{"messageId":"3046","fix":"3072","desc":"3048"},{"messageId":"3049","fix":"3073","desc":"3051"},{"messageId":"3046","fix":"3074","desc":"3048"},{"messageId":"3049","fix":"3075","desc":"3051"},{"messageId":"3046","fix":"3076","desc":"3048"},{"messageId":"3049","fix":"3077","desc":"3051"},{"messageId":"3046","fix":"3078","desc":"3048"},{"messageId":"3049","fix":"3079","desc":"3051"},{"messageId":"3046","fix":"3080","desc":"3048"},{"messageId":"3049","fix":"3081","desc":"3051"},{"messageId":"3046","fix":"3082","desc":"3048"},{"messageId":"3049","fix":"3083","desc":"3051"},{"messageId":"3046","fix":"3084","desc":"3048"},{"messageId":"3049","fix":"3085","desc":"3051"},{"messageId":"3046","fix":"3086","desc":"3048"},{"messageId":"3049","fix":"3087","desc":"3051"},{"messageId":"3046","fix":"3088","desc":"3048"},{"messageId":"3049","fix":"3089","desc":"3051"},{"messageId":"3046","fix":"3090","desc":"3048"},{"messageId":"3049","fix":"3091","desc":"3051"},{"messageId":"3046","fix":"3092","desc":"3048"},{"messageId":"3049","fix":"3093","desc":"3051"},{"messageId":"3046","fix":"3094","desc":"3048"},{"messageId":"3049","fix":"3095","desc":"3051"},{"messageId":"3046","fix":"3096","desc":"3048"},{"messageId":"3049","fix":"3097","desc":"3051"},{"messageId":"3046","fix":"3098","desc":"3048"},{"messageId":"3049","fix":"3099","desc":"3051"},{"messageId":"3046","fix":"3100","desc":"3048"},{"messageId":"3049","fix":"3101","desc":"3051"},{"messageId":"3046","fix":"3102","desc":"3048"},{"messageId":"3049","fix":"3103","desc":"3051"},{"messageId":"3046","fix":"3104","desc":"3048"},{"messageId":"3049","fix":"3105","desc":"3051"},{"messageId":"3046","fix":"3106","desc":"3048"},{"messageId":"3049","fix":"3107","desc":"3051"},{"messageId":"3046","fix":"3108","desc":"3048"},{"messageId":"3049","fix":"3109","desc":"3051"},{"messageId":"3046","fix":"3110","desc":"3048"},{"messageId":"3049","fix":"3111","desc":"3051"},{"messageId":"3046","fix":"3112","desc":"3048"},{"messageId":"3049","fix":"3113","desc":"3051"},{"messageId":"3046","fix":"3114","desc":"3048"},{"messageId":"3049","fix":"3115","desc":"3051"},{"messageId":"3046","fix":"3116","desc":"3048"},{"messageId":"3049","fix":"3117","desc":"3051"},{"messageId":"3046","fix":"3118","desc":"3048"},{"messageId":"3049","fix":"3119","desc":"3051"},{"messageId":"3046","fix":"3120","desc":"3048"},{"messageId":"3049","fix":"3121","desc":"3051"},{"messageId":"3046","fix":"3122","desc":"3048"},{"messageId":"3049","fix":"3123","desc":"3051"},{"messageId":"3046","fix":"3124","desc":"3048"},{"messageId":"3049","fix":"3125","desc":"3051"},{"messageId":"3046","fix":"3126","desc":"3048"},{"messageId":"3049","fix":"3127","desc":"3051"},{"messageId":"3046","fix":"3128","desc":"3048"},{"messageId":"3049","fix":"3129","desc":"3051"},{"messageId":"3046","fix":"3130","desc":"3048"},{"messageId":"3049","fix":"3131","desc":"3051"},{"messageId":"3046","fix":"3132","desc":"3048"},{"messageId":"3049","fix":"3133","desc":"3051"},{"messageId":"3046","fix":"3134","desc":"3048"},{"messageId":"3049","fix":"3135","desc":"3051"},{"messageId":"3046","fix":"3136","desc":"3048"},{"messageId":"3049","fix":"3137","desc":"3051"},{"messageId":"3046","fix":"3138","desc":"3048"},{"messageId":"3049","fix":"3139","desc":"3051"},{"messageId":"3046","fix":"3140","desc":"3048"},{"messageId":"3049","fix":"3141","desc":"3051"},{"messageId":"3142","fix":"3143","desc":"3144"},{"messageId":"3046","fix":"3145","desc":"3048"},{"messageId":"3049","fix":"3146","desc":"3051"},{"messageId":"3046","fix":"3147","desc":"3048"},{"messageId":"3049","fix":"3148","desc":"3051"},{"messageId":"3046","fix":"3149","desc":"3048"},{"messageId":"3049","fix":"3150","desc":"3051"},{"messageId":"3046","fix":"3151","desc":"3048"},{"messageId":"3049","fix":"3152","desc":"3051"},{"messageId":"3046","fix":"3153","desc":"3048"},{"messageId":"3049","fix":"3154","desc":"3051"},{"messageId":"3046","fix":"3155","desc":"3048"},{"messageId":"3049","fix":"3156","desc":"3051"},{"messageId":"3046","fix":"3157","desc":"3048"},{"messageId":"3049","fix":"3158","desc":"3051"},{"messageId":"3046","fix":"3159","desc":"3048"},{"messageId":"3049","fix":"3160","desc":"3051"},{"messageId":"3046","fix":"3161","desc":"3048"},{"messageId":"3049","fix":"3162","desc":"3051"},{"messageId":"3046","fix":"3163","desc":"3048"},{"messageId":"3049","fix":"3164","desc":"3051"},{"messageId":"3046","fix":"3165","desc":"3048"},{"messageId":"3049","fix":"3166","desc":"3051"},{"messageId":"3046","fix":"3167","desc":"3048"},{"messageId":"3049","fix":"3168","desc":"3051"},[414,425]," IdValuePair ",{"messageId":"3169","fix":"3170","desc":"3171"},{"messageId":"3172","fix":"3173","desc":"3174"},{"messageId":"3169","fix":"3175","desc":"3171"},{"messageId":"3172","fix":"3176","desc":"3174"},{"messageId":"3169","fix":"3177","desc":"3171"},{"messageId":"3172","fix":"3178","desc":"3174"},{"messageId":"3169","fix":"3179","desc":"3171"},{"messageId":"3172","fix":"3180","desc":"3174"},{"messageId":"3169","fix":"3181","desc":"3171"},{"messageId":"3172","fix":"3182","desc":"3174"},{"messageId":"3169","fix":"3183","desc":"3171"},{"messageId":"3172","fix":"3184","desc":"3174"},{"messageId":"3169","fix":"3185","desc":"3171"},{"messageId":"3172","fix":"3186","desc":"3174"},{"messageId":"3169","fix":"3187","desc":"3171"},{"messageId":"3172","fix":"3188","desc":"3174"},{"messageId":"3169","fix":"3189","desc":"3171"},{"messageId":"3172","fix":"3190","desc":"3174"},{"messageId":"3169","fix":"3191","desc":"3171"},{"messageId":"3172","fix":"3192","desc":"3174"},{"messageId":"3169","fix":"3193","desc":"3171"},{"messageId":"3172","fix":"3194","desc":"3174"},{"messageId":"3169","fix":"3195","desc":"3171"},{"messageId":"3172","fix":"3196","desc":"3174"},{"messageId":"3169","fix":"3197","desc":"3171"},{"messageId":"3172","fix":"3198","desc":"3174"},{"messageId":"3169","fix":"3199","desc":"3171"},{"messageId":"3172","fix":"3200","desc":"3174"},{"messageId":"3169","fix":"3201","desc":"3171"},{"messageId":"3172","fix":"3202","desc":"3174"},{"messageId":"3169","fix":"3203","desc":"3171"},{"messageId":"3172","fix":"3204","desc":"3174"},{"messageId":"3169","fix":"3205","desc":"3171"},{"messageId":"3172","fix":"3206","desc":"3174"},{"messageId":"3169","fix":"3207","desc":"3171"},{"messageId":"3172","fix":"3208","desc":"3174"},{"messageId":"3169","fix":"3209","desc":"3171"},{"messageId":"3172","fix":"3210","desc":"3174"},{"messageId":"3169","fix":"3211","desc":"3171"},{"messageId":"3172","fix":"3212","desc":"3174"},{"messageId":"3169","fix":"3213","desc":"3171"},{"messageId":"3172","fix":"3214","desc":"3174"},{"messageId":"3169","fix":"3215","desc":"3171"},{"messageId":"3172","fix":"3216","desc":"3174"},{"messageId":"3169","fix":"3217","desc":"3171"},{"messageId":"3172","fix":"3218","desc":"3174"},{"messageId":"3169","fix":"3219","desc":"3171"},{"messageId":"3172","fix":"3220","desc":"3174"},{"messageId":"3169","fix":"3221","desc":"3171"},{"messageId":"3172","fix":"3222","desc":"3174"},{"messageId":"3169","fix":"3223","desc":"3171"},{"messageId":"3172","fix":"3224","desc":"3174"},{"messageId":"3169","fix":"3225","desc":"3171"},{"messageId":"3172","fix":"3226","desc":"3174"},{"messageId":"3169","fix":"3227","desc":"3171"},{"messageId":"3172","fix":"3228","desc":"3174"},{"messageId":"3169","fix":"3229","desc":"3171"},{"messageId":"3172","fix":"3230","desc":"3174"},{"messageId":"3169","fix":"3231","desc":"3171"},{"messageId":"3172","fix":"3232","desc":"3174"},{"messageId":"3169","fix":"3233","desc":"3171"},{"messageId":"3172","fix":"3234","desc":"3174"},{"messageId":"3169","fix":"3235","desc":"3171"},{"messageId":"3172","fix":"3236","desc":"3174"},{"messageId":"3169","fix":"3237","desc":"3171"},{"messageId":"3172","fix":"3238","desc":"3174"},{"messageId":"3169","fix":"3239","desc":"3171"},{"messageId":"3172","fix":"3240","desc":"3174"},{"messageId":"3169","fix":"3241","desc":"3171"},{"messageId":"3172","fix":"3242","desc":"3174"},{"messageId":"3169","fix":"3243","desc":"3171"},{"messageId":"3172","fix":"3244","desc":"3174"},{"messageId":"3169","fix":"3245","desc":"3171"},{"messageId":"3172","fix":"3246","desc":"3174"},{"messageId":"3169","fix":"3247","desc":"3171"},{"messageId":"3172","fix":"3248","desc":"3174"},{"messageId":"3169","fix":"3249","desc":"3171"},{"messageId":"3172","fix":"3250","desc":"3174"},{"messageId":"3169","fix":"3251","desc":"3171"},{"messageId":"3172","fix":"3252","desc":"3174"},{"messageId":"3169","fix":"3253","desc":"3171"},{"messageId":"3172","fix":"3254","desc":"3174"},{"messageId":"3169","fix":"3255","desc":"3171"},{"messageId":"3172","fix":"3256","desc":"3174"},{"messageId":"3169","fix":"3257","desc":"3171"},{"messageId":"3172","fix":"3258","desc":"3174"},{"messageId":"3169","fix":"3259","desc":"3171"},{"messageId":"3172","fix":"3260","desc":"3174"},{"messageId":"3169","fix":"3261","desc":"3171"},{"messageId":"3172","fix":"3262","desc":"3174"},{"messageId":"3169","fix":"3263","desc":"3171"},{"messageId":"3172","fix":"3264","desc":"3174"},{"messageId":"3169","fix":"3265","desc":"3171"},{"messageId":"3172","fix":"3266","desc":"3174"},{"messageId":"3169","fix":"3267","desc":"3171"},{"messageId":"3172","fix":"3268","desc":"3174"},{"messageId":"3169","fix":"3269","desc":"3171"},{"messageId":"3172","fix":"3270","desc":"3174"},{"messageId":"3169","fix":"3271","desc":"3171"},{"messageId":"3172","fix":"3272","desc":"3174"},{"messageId":"3169","fix":"3273","desc":"3171"},{"messageId":"3172","fix":"3274","desc":"3174"},{"messageId":"3169","fix":"3275","desc":"3171"},{"messageId":"3172","fix":"3276","desc":"3174"},{"messageId":"3169","fix":"3277","desc":"3171"},{"messageId":"3172","fix":"3278","desc":"3174"},{"messageId":"3169","fix":"3279","desc":"3171"},{"messageId":"3172","fix":"3280","desc":"3174"},{"messageId":"3169","fix":"3281","desc":"3171"},{"messageId":"3172","fix":"3282","desc":"3174"},{"messageId":"3169","fix":"3283","desc":"3171"},{"messageId":"3172","fix":"3284","desc":"3174"},{"messageId":"3046","fix":"3285","desc":"3048"},{"messageId":"3049","fix":"3286","desc":"3051"},{"messageId":"3046","fix":"3287","desc":"3048"},{"messageId":"3049","fix":"3288","desc":"3051"},{"messageId":"3046","fix":"3289","desc":"3048"},{"messageId":"3049","fix":"3290","desc":"3051"},{"messageId":"3046","fix":"3291","desc":"3048"},{"messageId":"3049","fix":"3292","desc":"3051"},{"messageId":"3046","fix":"3293","desc":"3048"},{"messageId":"3049","fix":"3294","desc":"3051"},{"messageId":"3046","fix":"3295","desc":"3048"},{"messageId":"3049","fix":"3296","desc":"3051"},{"messageId":"3046","fix":"3297","desc":"3048"},{"messageId":"3049","fix":"3298","desc":"3051"},{"messageId":"3046","fix":"3299","desc":"3048"},{"messageId":"3049","fix":"3300","desc":"3051"},{"messageId":"3046","fix":"3301","desc":"3048"},{"messageId":"3049","fix":"3302","desc":"3051"},{"messageId":"3046","fix":"3303","desc":"3048"},{"messageId":"3049","fix":"3304","desc":"3051"},{"messageId":"3046","fix":"3305","desc":"3048"},{"messageId":"3049","fix":"3306","desc":"3051"},{"messageId":"3046","fix":"3307","desc":"3048"},{"messageId":"3049","fix":"3308","desc":"3051"},{"messageId":"3046","fix":"3309","desc":"3048"},{"messageId":"3049","fix":"3310","desc":"3051"},{"messageId":"3046","fix":"3311","desc":"3048"},{"messageId":"3049","fix":"3312","desc":"3051"},{"messageId":"3046","fix":"3313","desc":"3048"},{"messageId":"3049","fix":"3314","desc":"3051"},{"messageId":"3046","fix":"3315","desc":"3048"},{"messageId":"3049","fix":"3316","desc":"3051"},{"messageId":"3046","fix":"3317","desc":"3048"},{"messageId":"3049","fix":"3318","desc":"3051"},{"messageId":"3046","fix":"3319","desc":"3048"},{"messageId":"3049","fix":"3320","desc":"3051"},{"messageId":"3046","fix":"3321","desc":"3048"},{"messageId":"3049","fix":"3322","desc":"3051"},{"messageId":"3046","fix":"3323","desc":"3048"},{"messageId":"3049","fix":"3324","desc":"3051"},{"messageId":"3046","fix":"3325","desc":"3048"},{"messageId":"3049","fix":"3326","desc":"3051"},{"messageId":"3046","fix":"3327","desc":"3048"},{"messageId":"3049","fix":"3328","desc":"3051"},{"messageId":"3046","fix":"3329","desc":"3048"},{"messageId":"3049","fix":"3330","desc":"3051"},{"messageId":"3046","fix":"3331","desc":"3048"},{"messageId":"3049","fix":"3332","desc":"3051"},{"messageId":"3046","fix":"3333","desc":"3048"},{"messageId":"3049","fix":"3334","desc":"3051"},{"messageId":"3046","fix":"3335","desc":"3048"},{"messageId":"3049","fix":"3336","desc":"3051"},{"messageId":"3046","fix":"3337","desc":"3048"},{"messageId":"3049","fix":"3338","desc":"3051"},{"messageId":"3046","fix":"3339","desc":"3048"},{"messageId":"3049","fix":"3340","desc":"3051"},{"messageId":"3046","fix":"3341","desc":"3048"},{"messageId":"3049","fix":"3342","desc":"3051"},{"messageId":"3046","fix":"3343","desc":"3048"},{"messageId":"3049","fix":"3344","desc":"3051"},{"messageId":"3046","fix":"3345","desc":"3048"},{"messageId":"3049","fix":"3346","desc":"3051"},{"messageId":"3046","fix":"3347","desc":"3048"},{"messageId":"3049","fix":"3348","desc":"3051"},{"messageId":"3046","fix":"3349","desc":"3048"},{"messageId":"3049","fix":"3350","desc":"3051"},{"messageId":"3046","fix":"3351","desc":"3048"},{"messageId":"3049","fix":"3352","desc":"3051"},{"messageId":"3046","fix":"3353","desc":"3048"},{"messageId":"3049","fix":"3354","desc":"3051"},{"messageId":"3046","fix":"3355","desc":"3048"},{"messageId":"3049","fix":"3356","desc":"3051"},[16088,16089],"",{"messageId":"3046","fix":"3357","desc":"3048"},{"messageId":"3049","fix":"3358","desc":"3051"},{"messageId":"3046","fix":"3359","desc":"3048"},{"messageId":"3049","fix":"3360","desc":"3051"},{"messageId":"3046","fix":"3361","desc":"3048"},{"messageId":"3049","fix":"3362","desc":"3051"},{"messageId":"3046","fix":"3363","desc":"3048"},{"messageId":"3049","fix":"3364","desc":"3051"},{"messageId":"3046","fix":"3365","desc":"3048"},{"messageId":"3049","fix":"3366","desc":"3051"},{"messageId":"3046","fix":"3367","desc":"3048"},{"messageId":"3049","fix":"3368","desc":"3051"},{"messageId":"3046","fix":"3369","desc":"3048"},{"messageId":"3049","fix":"3370","desc":"3051"},{"messageId":"3046","fix":"3371","desc":"3048"},{"messageId":"3049","fix":"3372","desc":"3051"},{"messageId":"3046","fix":"3373","desc":"3048"},{"messageId":"3049","fix":"3374","desc":"3051"},{"messageId":"3046","fix":"3375","desc":"3048"},{"messageId":"3049","fix":"3376","desc":"3051"},{"messageId":"3046","fix":"3377","desc":"3048"},{"messageId":"3049","fix":"3378","desc":"3051"},{"messageId":"3046","fix":"3379","desc":"3048"},{"messageId":"3049","fix":"3380","desc":"3051"},{"messageId":"3046","fix":"3381","desc":"3048"},{"messageId":"3049","fix":"3382","desc":"3051"},{"messageId":"3046","fix":"3383","desc":"3048"},{"messageId":"3049","fix":"3384","desc":"3051"},{"messageId":"3046","fix":"3385","desc":"3048"},{"messageId":"3049","fix":"3386","desc":"3051"},{"messageId":"3046","fix":"3387","desc":"3048"},{"messageId":"3049","fix":"3388","desc":"3051"},{"messageId":"3046","fix":"3389","desc":"3048"},{"messageId":"3049","fix":"3390","desc":"3051"},{"messageId":"3046","fix":"3391","desc":"3048"},{"messageId":"3049","fix":"3392","desc":"3051"},{"messageId":"3046","fix":"3393","desc":"3048"},{"messageId":"3049","fix":"3394","desc":"3051"},{"messageId":"3046","fix":"3395","desc":"3048"},{"messageId":"3049","fix":"3396","desc":"3051"},{"messageId":"3046","fix":"3397","desc":"3048"},{"messageId":"3049","fix":"3398","desc":"3051"},{"messageId":"3046","fix":"3399","desc":"3048"},{"messageId":"3049","fix":"3400","desc":"3051"},{"messageId":"3046","fix":"3401","desc":"3048"},{"messageId":"3049","fix":"3402","desc":"3051"},{"messageId":"3046","fix":"3403","desc":"3048"},{"messageId":"3049","fix":"3404","desc":"3051"},{"messageId":"3046","fix":"3405","desc":"3048"},{"messageId":"3049","fix":"3406","desc":"3051"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3408","desc":"3048"},{"messageId":"3049","fix":"3409","desc":"3051"},{"messageId":"3046","fix":"3410","desc":"3048"},{"messageId":"3049","fix":"3411","desc":"3051"},{"messageId":"3046","fix":"3412","desc":"3048"},{"messageId":"3049","fix":"3413","desc":"3051"},{"messageId":"3046","fix":"3414","desc":"3048"},{"messageId":"3049","fix":"3415","desc":"3051"},{"messageId":"3046","fix":"3416","desc":"3048"},{"messageId":"3049","fix":"3417","desc":"3051"},{"messageId":"3046","fix":"3418","desc":"3048"},{"messageId":"3049","fix":"3419","desc":"3051"},{"messageId":"3046","fix":"3420","desc":"3048"},{"messageId":"3049","fix":"3421","desc":"3051"},{"messageId":"3046","fix":"3422","desc":"3048"},{"messageId":"3049","fix":"3423","desc":"3051"},{"messageId":"3046","fix":"3424","desc":"3048"},{"messageId":"3049","fix":"3425","desc":"3051"},{"messageId":"3046","fix":"3426","desc":"3048"},{"messageId":"3049","fix":"3427","desc":"3051"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3428","desc":"3048"},{"messageId":"3049","fix":"3429","desc":"3051"},{"messageId":"3046","fix":"3430","desc":"3048"},{"messageId":"3049","fix":"3431","desc":"3051"},{"messageId":"3046","fix":"3432","desc":"3048"},{"messageId":"3049","fix":"3433","desc":"3051"},{"messageId":"3046","fix":"3434","desc":"3048"},{"messageId":"3049","fix":"3435","desc":"3051"},{"messageId":"3046","fix":"3436","desc":"3048"},{"messageId":"3049","fix":"3437","desc":"3051"},{"messageId":"3046","fix":"3438","desc":"3048"},{"messageId":"3049","fix":"3439","desc":"3051"},{"messageId":"3046","fix":"3440","desc":"3048"},{"messageId":"3049","fix":"3441","desc":"3051"},{"messageId":"3046","fix":"3442","desc":"3048"},{"messageId":"3049","fix":"3443","desc":"3051"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3444","desc":"3048"},{"messageId":"3049","fix":"3445","desc":"3051"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3446","desc":"3048"},{"messageId":"3049","fix":"3447","desc":"3051"},{"messageId":"3046","fix":"3448","desc":"3048"},{"messageId":"3049","fix":"3449","desc":"3051"},{"messageId":"3046","fix":"3450","desc":"3048"},{"messageId":"3049","fix":"3451","desc":"3051"},{"messageId":"3046","fix":"3452","desc":"3048"},{"messageId":"3049","fix":"3453","desc":"3051"},{"messageId":"3046","fix":"3454","desc":"3048"},{"messageId":"3049","fix":"3455","desc":"3051"},{"messageId":"3046","fix":"3456","desc":"3048"},{"messageId":"3049","fix":"3457","desc":"3051"},{"messageId":"3046","fix":"3458","desc":"3048"},{"messageId":"3049","fix":"3459","desc":"3051"},{"messageId":"3046","fix":"3460","desc":"3048"},{"messageId":"3049","fix":"3461","desc":"3051"},{"messageId":"3046","fix":"3462","desc":"3048"},{"messageId":"3049","fix":"3463","desc":"3051"},{"messageId":"3046","fix":"3464","desc":"3048"},{"messageId":"3049","fix":"3465","desc":"3051"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3466","desc":"3048"},{"messageId":"3049","fix":"3467","desc":"3051"},{"messageId":"3046","fix":"3468","desc":"3048"},{"messageId":"3049","fix":"3469","desc":"3051"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3470","desc":"3048"},{"messageId":"3049","fix":"3471","desc":"3051"},{"messageId":"3046","fix":"3472","desc":"3048"},{"messageId":"3049","fix":"3473","desc":"3051"},{"messageId":"3046","fix":"3474","desc":"3048"},{"messageId":"3049","fix":"3475","desc":"3051"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3476","desc":"3048"},{"messageId":"3049","fix":"3477","desc":"3051"},{"messageId":"3046","fix":"3478","desc":"3048"},{"messageId":"3049","fix":"3479","desc":"3051"},{"messageId":"3046","fix":"3480","desc":"3048"},{"messageId":"3049","fix":"3481","desc":"3051"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3482","desc":"3048"},{"messageId":"3049","fix":"3483","desc":"3051"},{"messageId":"3046","fix":"3484","desc":"3048"},{"messageId":"3049","fix":"3485","desc":"3051"},{"messageId":"3046","fix":"3486","desc":"3048"},{"messageId":"3049","fix":"3487","desc":"3051"},{"messageId":"3046","fix":"3488","desc":"3048"},{"messageId":"3049","fix":"3489","desc":"3051"},{"messageId":"3046","fix":"3490","desc":"3048"},{"messageId":"3049","fix":"3491","desc":"3051"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3492","desc":"3048"},{"messageId":"3049","fix":"3493","desc":"3051"},{"messageId":"3046","fix":"3494","desc":"3048"},{"messageId":"3049","fix":"3495","desc":"3051"},{"messageId":"3046","fix":"3496","desc":"3048"},{"messageId":"3049","fix":"3497","desc":"3051"},{"messageId":"3142","fix":"3498","desc":"3144"},{"messageId":"3046","fix":"3499","desc":"3048"},{"messageId":"3049","fix":"3500","desc":"3051"},{"messageId":"3046","fix":"3501","desc":"3048"},{"messageId":"3049","fix":"3502","desc":"3051"},{"messageId":"3046","fix":"3503","desc":"3048"},{"messageId":"3049","fix":"3504","desc":"3051"},{"messageId":"3046","fix":"3505","desc":"3048"},{"messageId":"3049","fix":"3506","desc":"3051"},{"messageId":"3046","fix":"3507","desc":"3048"},{"messageId":"3049","fix":"3508","desc":"3051"},{"messageId":"3046","fix":"3509","desc":"3048"},{"messageId":"3049","fix":"3510","desc":"3051"},{"messageId":"3046","fix":"3511","desc":"3048"},{"messageId":"3049","fix":"3512","desc":"3051"},{"messageId":"3046","fix":"3513","desc":"3048"},{"messageId":"3049","fix":"3514","desc":"3051"},{"messageId":"3046","fix":"3515","desc":"3048"},{"messageId":"3049","fix":"3516","desc":"3051"},{"messageId":"3046","fix":"3517","desc":"3048"},{"messageId":"3049","fix":"3518","desc":"3051"},{"messageId":"3046","fix":"3519","desc":"3048"},{"messageId":"3049","fix":"3520","desc":"3051"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3521","desc":"3048"},{"messageId":"3049","fix":"3522","desc":"3051"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3523","desc":"3048"},{"messageId":"3049","fix":"3524","desc":"3051"},{"messageId":"3046","fix":"3525","desc":"3048"},{"messageId":"3049","fix":"3526","desc":"3051"},{"messageId":"3046","fix":"3527","desc":"3048"},{"messageId":"3049","fix":"3528","desc":"3051"},{"messageId":"3046","fix":"3529","desc":"3048"},{"messageId":"3049","fix":"3530","desc":"3051"},{"messageId":"3046","fix":"3531","desc":"3048"},{"messageId":"3049","fix":"3532","desc":"3051"},{"messageId":"3046","fix":"3533","desc":"3048"},{"messageId":"3049","fix":"3534","desc":"3051"},{"messageId":"3046","fix":"3535","desc":"3048"},{"messageId":"3049","fix":"3536","desc":"3051"},{"messageId":"3046","fix":"3537","desc":"3048"},{"messageId":"3049","fix":"3538","desc":"3051"},{"messageId":"3046","fix":"3539","desc":"3048"},{"messageId":"3049","fix":"3540","desc":"3051"},{"messageId":"3046","fix":"3541","desc":"3048"},{"messageId":"3049","fix":"3542","desc":"3051"},{"messageId":"3046","fix":"3543","desc":"3048"},{"messageId":"3049","fix":"3544","desc":"3051"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3545","desc":"3048"},{"messageId":"3049","fix":"3546","desc":"3051"},{"messageId":"3046","fix":"3547","desc":"3048"},{"messageId":"3049","fix":"3548","desc":"3051"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3549","desc":"3048"},{"messageId":"3049","fix":"3550","desc":"3051"},{"messageId":"3046","fix":"3551","desc":"3048"},{"messageId":"3049","fix":"3552","desc":"3051"},{"messageId":"3046","fix":"3553","desc":"3048"},{"messageId":"3049","fix":"3554","desc":"3051"},{"messageId":"3046","fix":"3555","desc":"3048"},{"messageId":"3049","fix":"3556","desc":"3051"},{"messageId":"3046","fix":"3557","desc":"3048"},{"messageId":"3049","fix":"3558","desc":"3051"},{"messageId":"3046","fix":"3559","desc":"3048"},{"messageId":"3049","fix":"3560","desc":"3051"},{"messageId":"3046","fix":"3561","desc":"3048"},{"messageId":"3049","fix":"3562","desc":"3051"},{"messageId":"3046","fix":"3563","desc":"3048"},{"messageId":"3049","fix":"3564","desc":"3051"},{"messageId":"3046","fix":"3565","desc":"3048"},{"messageId":"3049","fix":"3566","desc":"3051"},{"messageId":"3046","fix":"3567","desc":"3048"},{"messageId":"3049","fix":"3568","desc":"3051"},{"messageId":"3046","fix":"3569","desc":"3048"},{"messageId":"3049","fix":"3570","desc":"3051"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3571","desc":"3048"},{"messageId":"3049","fix":"3572","desc":"3051"},{"messageId":"3046","fix":"3573","desc":"3048"},{"messageId":"3049","fix":"3574","desc":"3051"},{"messageId":"3046","fix":"3575","desc":"3048"},{"messageId":"3049","fix":"3576","desc":"3051"},{"messageId":"3046","fix":"3577","desc":"3048"},{"messageId":"3049","fix":"3578","desc":"3051"},{"messageId":"3046","fix":"3579","desc":"3048"},{"messageId":"3049","fix":"3580","desc":"3051"},{"messageId":"3046","fix":"3581","desc":"3048"},{"messageId":"3049","fix":"3582","desc":"3051"},{"messageId":"3046","fix":"3583","desc":"3048"},{"messageId":"3049","fix":"3584","desc":"3051"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3585","desc":"3048"},{"messageId":"3049","fix":"3586","desc":"3051"},{"messageId":"3046","fix":"3587","desc":"3048"},{"messageId":"3049","fix":"3588","desc":"3051"},{"messageId":"3046","fix":"3589","desc":"3048"},{"messageId":"3049","fix":"3590","desc":"3051"},{"messageId":"3046","fix":"3591","desc":"3048"},{"messageId":"3049","fix":"3592","desc":"3051"},{"messageId":"3046","fix":"3593","desc":"3048"},{"messageId":"3049","fix":"3594","desc":"3051"},{"messageId":"3046","fix":"3595","desc":"3048"},{"messageId":"3049","fix":"3596","desc":"3051"},{"messageId":"3046","fix":"3597","desc":"3048"},{"messageId":"3049","fix":"3598","desc":"3051"},{"messageId":"3046","fix":"3599","desc":"3048"},{"messageId":"3049","fix":"3600","desc":"3051"},{"messageId":"3046","fix":"3601","desc":"3048"},{"messageId":"3049","fix":"3602","desc":"3051"},{"messageId":"3046","fix":"3603","desc":"3048"},{"messageId":"3049","fix":"3604","desc":"3051"},{"messageId":"3046","fix":"3605","desc":"3048"},{"messageId":"3049","fix":"3606","desc":"3051"},{"messageId":"3046","fix":"3607","desc":"3048"},{"messageId":"3049","fix":"3608","desc":"3051"},{"messageId":"3046","fix":"3609","desc":"3048"},{"messageId":"3049","fix":"3610","desc":"3051"},{"kind":"3407","justification":"2687"},{"messageId":"3046","fix":"3611","desc":"3048"},{"messageId":"3049","fix":"3612","desc":"3051"},{"messageId":"3046","fix":"3613","desc":"3048"},{"messageId":"3049","fix":"3614","desc":"3051"},{"messageId":"3046","fix":"3615","desc":"3048"},{"messageId":"3049","fix":"3616","desc":"3051"},{"messageId":"3046","fix":"3617","desc":"3048"},{"messageId":"3049","fix":"3618","desc":"3051"},{"messageId":"3046","fix":"3619","desc":"3048"},{"messageId":"3049","fix":"3620","desc":"3051"},{"messageId":"3046","fix":"3621","desc":"3048"},{"messageId":"3049","fix":"3622","desc":"3051"},{"messageId":"3046","fix":"3623","desc":"3048"},{"messageId":"3049","fix":"3624","desc":"3051"},{"messageId":"3046","fix":"3625","desc":"3048"},{"messageId":"3049","fix":"3626","desc":"3051"},{"messageId":"3046","fix":"3627","desc":"3048"},{"messageId":"3049","fix":"3628","desc":"3051"},{"messageId":"3046","fix":"3629","desc":"3048"},{"messageId":"3049","fix":"3630","desc":"3051"},{"messageId":"3046","fix":"3631","desc":"3048"},{"messageId":"3049","fix":"3632","desc":"3051"},{"messageId":"3046","fix":"3633","desc":"3048"},{"messageId":"3049","fix":"3634","desc":"3051"},{"messageId":"3046","fix":"3635","desc":"3048"},{"messageId":"3049","fix":"3636","desc":"3051"},{"messageId":"3046","fix":"3637","desc":"3048"},{"messageId":"3049","fix":"3638","desc":"3051"},{"messageId":"3046","fix":"3639","desc":"3048"},{"messageId":"3049","fix":"3640","desc":"3051"},"suggestUnknown",{"range":"3641","text":"3642"},"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct.","suggestNever",{"range":"3641","text":"3643"},"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of.",{"range":"3644","text":"3642"},{"range":"3644","text":"3643"},{"range":"3645","text":"3642"},{"range":"3645","text":"3643"},{"range":"3646","text":"3642"},{"range":"3646","text":"3643"},{"range":"3647","text":"3642"},{"range":"3647","text":"3643"},{"range":"3648","text":"3642"},{"range":"3648","text":"3643"},{"range":"3649","text":"3642"},{"range":"3649","text":"3643"},{"range":"3650","text":"3642"},{"range":"3650","text":"3643"},{"range":"3651","text":"3642"},{"range":"3651","text":"3643"},{"range":"3652","text":"3642"},{"range":"3652","text":"3643"},{"range":"3653","text":"3642"},{"range":"3653","text":"3643"},{"range":"3654","text":"3642"},{"range":"3654","text":"3643"},{"range":"3655","text":"3642"},{"range":"3655","text":"3643"},{"range":"3656","text":"3642"},{"range":"3656","text":"3643"},{"range":"3657","text":"3642"},{"range":"3657","text":"3643"},{"range":"3658","text":"3642"},{"range":"3658","text":"3643"},{"range":"3659","text":"3642"},{"range":"3659","text":"3643"},{"range":"3660","text":"3642"},{"range":"3660","text":"3643"},{"range":"3661","text":"3642"},{"range":"3661","text":"3643"},{"range":"3662","text":"3642"},{"range":"3662","text":"3643"},{"range":"3663","text":"3642"},{"range":"3663","text":"3643"},{"range":"3664","text":"3642"},{"range":"3664","text":"3643"},{"range":"3665","text":"3642"},{"range":"3665","text":"3643"},{"range":"3666","text":"3642"},{"range":"3666","text":"3643"},{"range":"3667","text":"3642"},{"range":"3667","text":"3643"},{"range":"3668","text":"3642"},{"range":"3668","text":"3643"},{"range":"3669","text":"3642"},{"range":"3669","text":"3643"},{"range":"3670","text":"3642"},{"range":"3670","text":"3643"},{"range":"3671","text":"3642"},{"range":"3671","text":"3643"},{"range":"3672","text":"3642"},{"range":"3672","text":"3643"},{"range":"3673","text":"3642"},{"range":"3673","text":"3643"},{"range":"3674","text":"3642"},{"range":"3674","text":"3643"},{"range":"3675","text":"3642"},{"range":"3675","text":"3643"},{"range":"3676","text":"3642"},{"range":"3676","text":"3643"},{"range":"3677","text":"3642"},{"range":"3677","text":"3643"},{"range":"3678","text":"3642"},{"range":"3678","text":"3643"},{"range":"3679","text":"3642"},{"range":"3679","text":"3643"},{"range":"3680","text":"3642"},{"range":"3680","text":"3643"},{"range":"3681","text":"3642"},{"range":"3681","text":"3643"},{"range":"3682","text":"3642"},{"range":"3682","text":"3643"},{"range":"3683","text":"3642"},{"range":"3683","text":"3643"},{"range":"3684","text":"3642"},{"range":"3684","text":"3643"},{"range":"3685","text":"3642"},{"range":"3685","text":"3643"},{"range":"3686","text":"3642"},{"range":"3686","text":"3643"},{"range":"3687","text":"3642"},{"range":"3687","text":"3643"},{"range":"3688","text":"3642"},{"range":"3688","text":"3643"},"suggestOptionalChain",{"range":"3689","text":"3690"},"Consider using the optional chain operator `?.` instead. This operator includes runtime checks, so it is safer than the compile-only non-null assertion operator.",{"range":"3691","text":"3642"},{"range":"3691","text":"3643"},{"range":"3692","text":"3642"},{"range":"3692","text":"3643"},{"range":"3693","text":"3642"},{"range":"3693","text":"3643"},{"range":"3694","text":"3642"},{"range":"3694","text":"3643"},{"range":"3695","text":"3642"},{"range":"3695","text":"3643"},{"range":"3696","text":"3642"},{"range":"3696","text":"3643"},{"range":"3697","text":"3642"},{"range":"3697","text":"3643"},{"range":"3698","text":"3642"},{"range":"3698","text":"3643"},{"range":"3699","text":"3642"},{"range":"3699","text":"3643"},{"range":"3700","text":"3642"},{"range":"3700","text":"3643"},{"range":"3701","text":"3642"},{"range":"3701","text":"3643"},{"range":"3702","text":"3642"},{"range":"3702","text":"3643"},"removeEscape",{"range":"3703","text":"2687"},"Remove the `\\`. This maintains the current functionality.","escapeBackslash",{"range":"3704","text":"3705"},"Replace the `\\` with `\\\\` to include the actual backslash character.",{"range":"3706","text":"2687"},{"range":"3707","text":"3705"},{"range":"3708","text":"2687"},{"range":"3709","text":"3705"},{"range":"3710","text":"2687"},{"range":"3711","text":"3705"},{"range":"3712","text":"2687"},{"range":"3713","text":"3705"},{"range":"3714","text":"2687"},{"range":"3715","text":"3705"},{"range":"3716","text":"2687"},{"range":"3717","text":"3705"},{"range":"3718","text":"2687"},{"range":"3719","text":"3705"},{"range":"3720","text":"2687"},{"range":"3721","text":"3705"},{"range":"3722","text":"2687"},{"range":"3723","text":"3705"},{"range":"3724","text":"2687"},{"range":"3725","text":"3705"},{"range":"3726","text":"2687"},{"range":"3727","text":"3705"},{"range":"3728","text":"2687"},{"range":"3729","text":"3705"},{"range":"3730","text":"2687"},{"range":"3731","text":"3705"},{"range":"3732","text":"2687"},{"range":"3733","text":"3705"},{"range":"3734","text":"2687"},{"range":"3735","text":"3705"},{"range":"3736","text":"2687"},{"range":"3737","text":"3705"},{"range":"3738","text":"2687"},{"range":"3739","text":"3705"},{"range":"3740","text":"2687"},{"range":"3741","text":"3705"},{"range":"3742","text":"2687"},{"range":"3743","text":"3705"},{"range":"3744","text":"2687"},{"range":"3745","text":"3705"},{"range":"3746","text":"2687"},{"range":"3747","text":"3705"},{"range":"3748","text":"2687"},{"range":"3749","text":"3705"},{"range":"3750","text":"2687"},{"range":"3751","text":"3705"},{"range":"3752","text":"2687"},{"range":"3753","text":"3705"},{"range":"3754","text":"2687"},{"range":"3755","text":"3705"},{"range":"3756","text":"2687"},{"range":"3757","text":"3705"},{"range":"3758","text":"2687"},{"range":"3759","text":"3705"},{"range":"3760","text":"2687"},{"range":"3761","text":"3705"},{"range":"3762","text":"2687"},{"range":"3763","text":"3705"},{"range":"3764","text":"2687"},{"range":"3765","text":"3705"},{"range":"3766","text":"2687"},{"range":"3767","text":"3705"},{"range":"3768","text":"2687"},{"range":"3769","text":"3705"},{"range":"3770","text":"2687"},{"range":"3771","text":"3705"},{"range":"3772","text":"2687"},{"range":"3773","text":"3705"},{"range":"3774","text":"2687"},{"range":"3775","text":"3705"},{"range":"3776","text":"2687"},{"range":"3777","text":"3705"},{"range":"3778","text":"2687"},{"range":"3779","text":"3705"},{"range":"3780","text":"2687"},{"range":"3781","text":"3705"},{"range":"3782","text":"2687"},{"range":"3783","text":"3705"},{"range":"3784","text":"2687"},{"range":"3785","text":"3705"},{"range":"3786","text":"2687"},{"range":"3787","text":"3705"},{"range":"3788","text":"2687"},{"range":"3789","text":"3705"},{"range":"3790","text":"2687"},{"range":"3791","text":"3705"},{"range":"3792","text":"2687"},{"range":"3793","text":"3705"},{"range":"3794","text":"2687"},{"range":"3795","text":"3705"},{"range":"3796","text":"2687"},{"range":"3797","text":"3705"},{"range":"3798","text":"2687"},{"range":"3799","text":"3705"},{"range":"3800","text":"2687"},{"range":"3801","text":"3705"},{"range":"3802","text":"2687"},{"range":"3803","text":"3705"},{"range":"3804","text":"2687"},{"range":"3805","text":"3705"},{"range":"3806","text":"2687"},{"range":"3807","text":"3705"},{"range":"3808","text":"2687"},{"range":"3809","text":"3705"},{"range":"3810","text":"2687"},{"range":"3811","text":"3705"},{"range":"3812","text":"2687"},{"range":"3813","text":"3705"},{"range":"3814","text":"2687"},{"range":"3815","text":"3705"},{"range":"3816","text":"3642"},{"range":"3816","text":"3643"},{"range":"3817","text":"3642"},{"range":"3817","text":"3643"},{"range":"3818","text":"3642"},{"range":"3818","text":"3643"},{"range":"3819","text":"3642"},{"range":"3819","text":"3643"},{"range":"3820","text":"3642"},{"range":"3820","text":"3643"},{"range":"3821","text":"3642"},{"range":"3821","text":"3643"},{"range":"3822","text":"3642"},{"range":"3822","text":"3643"},{"range":"3823","text":"3642"},{"range":"3823","text":"3643"},{"range":"3824","text":"3642"},{"range":"3824","text":"3643"},{"range":"3825","text":"3642"},{"range":"3825","text":"3643"},{"range":"3826","text":"3642"},{"range":"3826","text":"3643"},{"range":"3827","text":"3642"},{"range":"3827","text":"3643"},{"range":"3828","text":"3642"},{"range":"3828","text":"3643"},{"range":"3829","text":"3642"},{"range":"3829","text":"3643"},{"range":"3830","text":"3642"},{"range":"3830","text":"3643"},{"range":"3831","text":"3642"},{"range":"3831","text":"3643"},{"range":"3832","text":"3642"},{"range":"3832","text":"3643"},{"range":"3833","text":"3642"},{"range":"3833","text":"3643"},{"range":"3834","text":"3642"},{"range":"3834","text":"3643"},{"range":"3835","text":"3642"},{"range":"3835","text":"3643"},{"range":"3836","text":"3642"},{"range":"3836","text":"3643"},{"range":"3837","text":"3642"},{"range":"3837","text":"3643"},{"range":"3838","text":"3642"},{"range":"3838","text":"3643"},{"range":"3839","text":"3642"},{"range":"3839","text":"3643"},{"range":"3840","text":"3642"},{"range":"3840","text":"3643"},{"range":"3841","text":"3642"},{"range":"3841","text":"3643"},{"range":"3842","text":"3642"},{"range":"3842","text":"3643"},{"range":"3843","text":"3642"},{"range":"3843","text":"3643"},{"range":"3844","text":"3642"},{"range":"3844","text":"3643"},{"range":"3845","text":"3642"},{"range":"3845","text":"3643"},{"range":"3846","text":"3642"},{"range":"3846","text":"3643"},{"range":"3847","text":"3642"},{"range":"3847","text":"3643"},{"range":"3848","text":"3642"},{"range":"3848","text":"3643"},{"range":"3849","text":"3642"},{"range":"3849","text":"3643"},{"range":"3850","text":"3642"},{"range":"3850","text":"3643"},{"range":"3851","text":"3642"},{"range":"3851","text":"3643"},{"range":"3852","text":"3642"},{"range":"3852","text":"3643"},{"range":"3853","text":"3642"},{"range":"3853","text":"3643"},{"range":"3854","text":"3642"},{"range":"3854","text":"3643"},{"range":"3855","text":"3642"},{"range":"3855","text":"3643"},{"range":"3856","text":"3642"},{"range":"3856","text":"3643"},{"range":"3857","text":"3642"},{"range":"3857","text":"3643"},{"range":"3858","text":"3642"},{"range":"3858","text":"3643"},{"range":"3859","text":"3642"},{"range":"3859","text":"3643"},{"range":"3860","text":"3642"},{"range":"3860","text":"3643"},{"range":"3861","text":"3642"},{"range":"3861","text":"3643"},{"range":"3862","text":"3642"},{"range":"3862","text":"3643"},{"range":"3863","text":"3642"},{"range":"3863","text":"3643"},{"range":"3864","text":"3642"},{"range":"3864","text":"3643"},{"range":"3865","text":"3642"},{"range":"3865","text":"3643"},{"range":"3866","text":"3642"},{"range":"3866","text":"3643"},{"range":"3867","text":"3642"},{"range":"3867","text":"3643"},{"range":"3868","text":"3642"},{"range":"3868","text":"3643"},{"range":"3869","text":"3642"},{"range":"3869","text":"3643"},{"range":"3870","text":"3642"},{"range":"3870","text":"3643"},{"range":"3871","text":"3642"},{"range":"3871","text":"3643"},{"range":"3872","text":"3642"},{"range":"3872","text":"3643"},{"range":"3873","text":"3642"},{"range":"3873","text":"3643"},{"range":"3874","text":"3642"},{"range":"3874","text":"3643"},{"range":"3875","text":"3642"},{"range":"3875","text":"3643"},{"range":"3876","text":"3642"},{"range":"3876","text":"3643"},"directive",{"range":"3877","text":"3642"},{"range":"3877","text":"3643"},{"range":"3878","text":"3642"},{"range":"3878","text":"3643"},{"range":"3879","text":"3642"},{"range":"3879","text":"3643"},{"range":"3880","text":"3642"},{"range":"3880","text":"3643"},{"range":"3881","text":"3642"},{"range":"3881","text":"3643"},{"range":"3882","text":"3642"},{"range":"3882","text":"3643"},{"range":"3883","text":"3642"},{"range":"3883","text":"3643"},{"range":"3884","text":"3642"},{"range":"3884","text":"3643"},{"range":"3885","text":"3642"},{"range":"3885","text":"3643"},{"range":"3886","text":"3642"},{"range":"3886","text":"3643"},{"range":"3887","text":"3642"},{"range":"3887","text":"3643"},{"range":"3888","text":"3642"},{"range":"3888","text":"3643"},{"range":"3889","text":"3642"},{"range":"3889","text":"3643"},{"range":"3890","text":"3642"},{"range":"3890","text":"3643"},{"range":"3891","text":"3642"},{"range":"3891","text":"3643"},{"range":"3892","text":"3642"},{"range":"3892","text":"3643"},{"range":"3893","text":"3642"},{"range":"3893","text":"3643"},{"range":"3894","text":"3642"},{"range":"3894","text":"3643"},{"range":"3895","text":"3642"},{"range":"3895","text":"3643"},{"range":"3896","text":"3642"},{"range":"3896","text":"3643"},{"range":"3897","text":"3642"},{"range":"3897","text":"3643"},{"range":"3898","text":"3642"},{"range":"3898","text":"3643"},{"range":"3899","text":"3642"},{"range":"3899","text":"3643"},{"range":"3900","text":"3642"},{"range":"3900","text":"3643"},{"range":"3901","text":"3642"},{"range":"3901","text":"3643"},{"range":"3902","text":"3642"},{"range":"3902","text":"3643"},{"range":"3903","text":"3642"},{"range":"3903","text":"3643"},{"range":"3904","text":"3642"},{"range":"3904","text":"3643"},{"range":"3905","text":"3642"},{"range":"3905","text":"3643"},{"range":"3906","text":"3642"},{"range":"3906","text":"3643"},{"range":"3907","text":"3642"},{"range":"3907","text":"3643"},{"range":"3908","text":"3642"},{"range":"3908","text":"3643"},{"range":"3909","text":"3642"},{"range":"3909","text":"3643"},{"range":"3910","text":"3642"},{"range":"3910","text":"3643"},{"range":"3911","text":"3642"},{"range":"3911","text":"3643"},{"range":"3912","text":"3642"},{"range":"3912","text":"3643"},{"range":"3913","text":"3642"},{"range":"3913","text":"3643"},{"range":"3914","text":"3642"},{"range":"3914","text":"3643"},{"range":"3915","text":"3642"},{"range":"3915","text":"3643"},{"range":"3916","text":"3642"},{"range":"3916","text":"3643"},{"range":"3917","text":"3642"},{"range":"3917","text":"3643"},{"range":"3918","text":"3642"},{"range":"3918","text":"3643"},{"range":"3919","text":"3642"},{"range":"3919","text":"3643"},{"range":"3920","text":"3642"},{"range":"3920","text":"3643"},{"range":"3921","text":"3642"},{"range":"3921","text":"3643"},{"range":"3922","text":"3690"},{"range":"3923","text":"3642"},{"range":"3923","text":"3643"},{"range":"3924","text":"3642"},{"range":"3924","text":"3643"},{"range":"3925","text":"3642"},{"range":"3925","text":"3643"},{"range":"3926","text":"3642"},{"range":"3926","text":"3643"},{"range":"3927","text":"3642"},{"range":"3927","text":"3643"},{"range":"3928","text":"3642"},{"range":"3928","text":"3643"},{"range":"3929","text":"3642"},{"range":"3929","text":"3643"},{"range":"3930","text":"3642"},{"range":"3930","text":"3643"},{"range":"3931","text":"3642"},{"range":"3931","text":"3643"},{"range":"3932","text":"3642"},{"range":"3932","text":"3643"},{"range":"3933","text":"3642"},{"range":"3933","text":"3643"},{"range":"3934","text":"3642"},{"range":"3934","text":"3643"},{"range":"3935","text":"3642"},{"range":"3935","text":"3643"},{"range":"3936","text":"3642"},{"range":"3936","text":"3643"},{"range":"3937","text":"3642"},{"range":"3937","text":"3643"},{"range":"3938","text":"3642"},{"range":"3938","text":"3643"},{"range":"3939","text":"3642"},{"range":"3939","text":"3643"},{"range":"3940","text":"3642"},{"range":"3940","text":"3643"},{"range":"3941","text":"3642"},{"range":"3941","text":"3643"},{"range":"3942","text":"3642"},{"range":"3942","text":"3643"},{"range":"3943","text":"3642"},{"range":"3943","text":"3643"},{"range":"3944","text":"3642"},{"range":"3944","text":"3643"},{"range":"3945","text":"3642"},{"range":"3945","text":"3643"},{"range":"3946","text":"3642"},{"range":"3946","text":"3643"},{"range":"3947","text":"3642"},{"range":"3947","text":"3643"},{"range":"3948","text":"3642"},{"range":"3948","text":"3643"},{"range":"3949","text":"3642"},{"range":"3949","text":"3643"},{"range":"3950","text":"3642"},{"range":"3950","text":"3643"},{"range":"3951","text":"3642"},{"range":"3951","text":"3643"},{"range":"3952","text":"3642"},{"range":"3952","text":"3643"},{"range":"3953","text":"3642"},{"range":"3953","text":"3643"},{"range":"3954","text":"3642"},{"range":"3954","text":"3643"},{"range":"3955","text":"3642"},{"range":"3955","text":"3643"},{"range":"3956","text":"3642"},{"range":"3956","text":"3643"},{"range":"3957","text":"3642"},{"range":"3957","text":"3643"},{"range":"3958","text":"3642"},{"range":"3958","text":"3643"},{"range":"3959","text":"3642"},{"range":"3959","text":"3643"},{"range":"3960","text":"3642"},{"range":"3960","text":"3643"},{"range":"3961","text":"3642"},{"range":"3961","text":"3643"},{"range":"3962","text":"3642"},{"range":"3962","text":"3643"},{"range":"3963","text":"3642"},{"range":"3963","text":"3643"},{"range":"3964","text":"3642"},{"range":"3964","text":"3643"},{"range":"3965","text":"3642"},{"range":"3965","text":"3643"},{"range":"3966","text":"3642"},{"range":"3966","text":"3643"},{"range":"3967","text":"3642"},{"range":"3967","text":"3643"},{"range":"3968","text":"3642"},{"range":"3968","text":"3643"},{"range":"3969","text":"3642"},{"range":"3969","text":"3643"},{"range":"3970","text":"3642"},{"range":"3970","text":"3643"},{"range":"3971","text":"3642"},{"range":"3971","text":"3643"},{"range":"3972","text":"3642"},{"range":"3972","text":"3643"},{"range":"3973","text":"3642"},{"range":"3973","text":"3643"},{"range":"3974","text":"3642"},{"range":"3974","text":"3643"},{"range":"3975","text":"3642"},{"range":"3975","text":"3643"},{"range":"3976","text":"3642"},{"range":"3976","text":"3643"},{"range":"3977","text":"3642"},{"range":"3977","text":"3643"},{"range":"3978","text":"3642"},{"range":"3978","text":"3643"},{"range":"3979","text":"3642"},{"range":"3979","text":"3643"},{"range":"3980","text":"3642"},{"range":"3980","text":"3643"},{"range":"3981","text":"3642"},{"range":"3981","text":"3643"},{"range":"3982","text":"3642"},{"range":"3982","text":"3643"},{"range":"3983","text":"3642"},{"range":"3983","text":"3643"},{"range":"3984","text":"3642"},{"range":"3984","text":"3643"},{"range":"3985","text":"3642"},{"range":"3985","text":"3643"},{"range":"3986","text":"3642"},{"range":"3986","text":"3643"},{"range":"3987","text":"3642"},{"range":"3987","text":"3643"},{"range":"3988","text":"3642"},{"range":"3988","text":"3643"},{"range":"3989","text":"3642"},{"range":"3989","text":"3643"},{"range":"3990","text":"3642"},{"range":"3990","text":"3643"},{"range":"3991","text":"3642"},{"range":"3991","text":"3643"},{"range":"3992","text":"3642"},{"range":"3992","text":"3643"},{"range":"3993","text":"3642"},{"range":"3993","text":"3643"},[25508,25511],"unknown","never",[683,686],[6549,6552],[7583,7586],[8410,8413],[8699,8702],[14583,14586],[15764,15767],[16551,16554],[17120,17123],[334,337],[1592,1595],[250,253],[632,635],[1102,1105],[1121,1124],[1654,1657],[2841,2844],[2860,2863],[1003,1006],[2844,2847],[3799,3802],[1123,1126],[1388,1391],[3227,3230],[8750,8753],[13653,13656],[14176,14179],[16241,16244],[35305,35308],[7192,7195],[7370,7373],[6080,6083],[12636,12639],[14692,14695],[666,669],[736,739],[804,807],[1928,1931],[20438,20441],[23126,23129],[23910,23913],[29190,29193],[3573,3576],[3655,3658],[5784,5787],[6277,6278],"?",[1021,1024],[6080,6083],[6119,6122],[6182,6185],[6305,6308],[6344,6347],[6498,6501],[6525,6528],[7118,7121],[40187,40190],[41762,41765],[2322,2325],[11854,11855],[11854,11854],"\\",[11879,11880],[11879,11879],[11896,11897],[11896,11896],[11903,11904],[11903,11903],[11908,11909],[11908,11908],[11910,11911],[11910,11910],[11915,11916],[11915,11915],[11924,11925],[11924,11924],[11941,11942],[11941,11941],[11950,11951],[11950,11950],[11955,11956],[11955,11955],[11957,11958],[11957,11957],[11962,11963],[11962,11962],[11969,11970],[11969,11969],[11986,11987],[11986,11986],[11993,11994],[11993,11993],[11998,11999],[11998,11998],[12000,12001],[12000,12000],[12005,12006],[12005,12005],[12020,12021],[12020,12020],[12038,12039],[12038,12038],[12053,12054],[12053,12053],[12066,12067],[12066,12066],[12081,12082],[12081,12081],[12087,12088],[12087,12087],[12089,12090],[12089,12089],[12098,12099],[12098,12098],[12113,12114],[12113,12113],[12268,12269],[12268,12268],[12295,12296],[12295,12295],[12314,12315],[12314,12314],[12321,12322],[12321,12321],[12326,12327],[12326,12326],[12328,12329],[12328,12328],[12335,12336],[12335,12335],[12348,12349],[12348,12348],[12367,12368],[12367,12367],[12376,12377],[12376,12376],[12381,12382],[12381,12381],[12383,12384],[12383,12383],[12390,12391],[12390,12390],[12401,12402],[12401,12401],[12420,12421],[12420,12420],[12427,12428],[12427,12427],[12432,12433],[12432,12432],[12434,12435],[12434,12434],[12441,12442],[12441,12441],[12460,12461],[12460,12460],[12480,12481],[12480,12480],[12495,12496],[12495,12495],[12508,12509],[12508,12508],[12523,12524],[12523,12523],[12529,12530],[12529,12529],[12531,12532],[12531,12531],[12540,12541],[12540,12540],[12555,12556],[12555,12555],[8379,8382],[4489,4492],[16767,16770],[27450,27453],[27503,27506],[27576,27579],[27951,27954],[28634,28637],[28688,28691],[29791,29794],[29821,29824],[8719,8722],[8782,8785],[32306,32309],[32346,32349],[32371,32374],[32390,32393],[32408,32411],[32745,32748],[32869,32872],[33371,33374],[33513,33516],[34004,34007],[34130,34133],[311,314],[1735,1738],[1888,1891],[11643,11646],[11676,11679],[11975,11978],[19286,19289],[2154,2157],[5171,5174],[5747,5750],[6323,6326],[2242,2245],[1026,1029],[9393,9396],[15400,15403],[17701,17704],[17819,17822],[19540,19543],[19563,19566],[14650,14653],[728,731],[1481,1484],[683,686],[1066,1069],[1095,1098],[1158,1161],[1180,1183],[1252,1255],[1269,1272],[1281,1284],[1430,1433],[1459,1462],[1526,1529],[4017,4020],[4338,4341],[2003,2006],[25569,25572],[683,686],[6549,6552],[7583,7586],[8410,8413],[8699,8702],[14583,14586],[15764,15767],[16551,16554],[17120,17123],[334,337],[1592,1595],[250,253],[632,635],[1163,1166],[1182,1185],[1715,1718],[2902,2905],[2921,2924],[1075,1078],[2844,2847],[3799,3802],[1257,1260],[1522,1525],[3361,3364],[8884,8887],[13787,13790],[14310,14313],[16415,16418],[35479,35482],[17963,17966],[18141,18144],[572,575],[7163,7166],[9219,9222],[666,669],[736,739],[804,807],[2043,2046],[20816,20819],[23511,23514],[24295,24298],[29575,29578],[3406,3409],[3488,3491],[5617,5620],[6110,6111],[1021,1024],[6080,6083],[6119,6122],[6182,6185],[6305,6308],[6344,6347],[6498,6501],[6525,6528],[7118,7121],[40349,40352],[41924,41927],[2389,2392],[8379,8382],[4490,4493],[16849,16852],[27532,27535],[27585,27588],[27658,27661],[28033,28036],[28716,28719],[28770,28773],[29873,29876],[29903,29906],[8855,8858],[8918,8921],[32398,32401],[32438,32441],[32463,32466],[32482,32485],[32500,32503],[32837,32840],[32961,32964],[33463,33466],[33605,33608],[34096,34099],[34222,34225],[311,314],[1735,1738],[1888,1891],[11772,11775],[11805,11808],[12104,12107],[19415,19418],[2156,2159],[5173,5176],[5749,5752],[6325,6328],[2259,2262],[1026,1029],[7216,7219],[9563,9566],[17701,17704],[17819,17822],[19060,19063],[19083,19086],[15032,15035],[728,731],[1481,1484],[1074,1077],[1095,1098],[1158,1161],[1180,1183],[1252,1255],[1269,1272],[1281,1284],[1430,1433],[1459,1462],[1526,1529],[4017,4020],[4338,4341],[2003,2006]] \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ddec728..96df6bc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,6 +2,10 @@ name: build on: [push, workflow_dispatch] +permissions: + contents: write + id-token: write + jobs: build: uses: datavisyn/github-workflows/.github/workflows/build-node-python.yml@main diff --git a/coral/__init__.py b/coral/__init__.py index 9f43879..0eaba97 100644 --- a/coral/__init__.py +++ b/coral/__init__.py @@ -5,7 +5,7 @@ ############################################################################### from os import path -from tdp_core.plugin.model import AVisynPlugin, RegHelper +from visyn_core.plugin.model import AVisynPlugin, RegHelper from .settings import CoralSettings diff --git a/coral/migration/env.py b/coral/migration/env.py index 98295d2..5a09426 100644 --- a/coral/migration/env.py +++ b/coral/migration/env.py @@ -1,3 +1,3 @@ -import tdp_core.dbmigration.env +import visyn_core.dbmigration.env -tdp_core.dbmigration.env.run_migrations_online() +visyn_core.dbmigration.env.run_migrations_online() diff --git a/coral/migration/versions/20220414_1158_ddd776aa28c3_.py b/coral/migration/versions/20220414_1158_ddd776aa28c3_.py index 786920b..6e31ab5 100644 --- a/coral/migration/versions/20220414_1158_ddd776aa28c3_.py +++ b/coral/migration/versions/20220414_1158_ddd776aa28c3_.py @@ -19,7 +19,7 @@ def upgrade(): for cmd in [ """ CREATE SCHEMA IF NOT EXISTS cohort; -CREATE SEQUENCE cohort.cohort_id_seq +CREATE SEQUENCE IF NOT EXISTS cohort.cohort_id_seq INCREMENT 1 START 1 MINVALUE 1 @@ -27,7 +27,7 @@ def upgrade(): CACHE 1; """, """ -CREATE TABLE cohort.cohort +CREATE TABLE IF NOT EXISTS cohort.cohort ( id integer NOT NULL DEFAULT nextval('cohort.cohort_id_seq'::regclass), name character varying COLLATE pg_catalog."default" NOT NULL, diff --git a/coral/settings.py b/coral/settings.py index b1adcbb..3526516 100644 --- a/coral/settings.py +++ b/coral/settings.py @@ -1,5 +1,5 @@ from pydantic import BaseModel -from tdp_core import manager +from visyn_core import manager class CoralSettings(BaseModel): diff --git a/coral/sql.py b/coral/sql.py index a51ce6a..f703f4a 100644 --- a/coral/sql.py +++ b/coral/sql.py @@ -1,7 +1,7 @@ import logging from flask import Flask, abort, jsonify, request -from tdp_core.security import login_required +from visyn_core.security import login_required from .settings import get_settings from .sql_query_mapper import QueryElements diff --git a/coral/sql_query_mapper.py b/coral/sql_query_mapper.py index f2dca51..c73c2da 100644 --- a/coral/sql_query_mapper.py +++ b/coral/sql_query_mapper.py @@ -7,7 +7,7 @@ from sqlalchemy import create_engine, exc, inspect, text from sqlalchemy.exc import NoInspectionAvailable from sqlalchemy.orm import sessionmaker -from tdp_core import manager +from visyn_core import manager from .settings import get_settings from .sql_tables import Cohort diff --git a/coral/tests/conftest.py b/coral/tests/conftest.py index 73deb4f..9db3a89 100755 --- a/coral/tests/conftest.py +++ b/coral/tests/conftest.py @@ -1,10 +1,10 @@ import pytest from fastapi import FastAPI from fastapi.testclient import TestClient -from tdp_core.security.manager import SecurityManager -from tdp_core.security.model import User -from tdp_core.server.visyn_server import create_visyn_server -from tdp_core.tests.fixtures.postgres_db import postgres_db +from visyn_core.security.manager import SecurityManager +from visyn_core.security.model import User +from visyn_core.server.visyn_server import create_visyn_server +from visyn_core.tests.fixtures.postgres_db import postgres_db assert postgres_db # silence unused import warning diff --git a/package.json b/package.json index 3db55f2..512c61d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "coral", "description": "Coral is a web-based cohort analysis tool to interactively create, refine, and analyze patient cohorts.", "homepage": "https://caleydo.org", - "version": "4.1.0", + "version": "5.0.0", "author": { "name": "PatrickAdelberger", "email": "coral@caleydo.org", @@ -32,7 +32,7 @@ "dist": "mkdir lib && cd dist && tar cvzf ../lib/bundle.tar.gz *", "docs": "visyn_scripts docs", "lint:fix": "visyn_scripts lint --fix", - "lint": "visyn_scripts lint || true", + "lint": "visyn_scripts lint", "prepack": "yarn run build", "start": "visyn_scripts start --env workspace_mode=single", "storybook:build": "NODE_OPTIONS=--max_old_space_size=4096 build-storybook", @@ -72,27 +72,30 @@ "react-dom": "^16.13.0", "react-router-dom": "^5.2.0", "split-grid": "^1.0.9", - "tdp_core": "^17.0.0", - "tdp_publicdb": "git+ssh://git@github.com/caleydo/tdp_publicdb#semver:^13.0.3", + "tdp_core": "^20.1.0", + "tdp_publicdb": "git+ssh://git@github.com:Caleydo/tdp_publicdb#semver:^14.0.0", "tippy.js": "^6.2.6", - "tourdino": "git+ssh://git@github.com/caleydo/tourdino#semver:^7.0.1", + "tourdino": "git+ssh://git@github.com:Caleydo/tourdino#semver:^8.0.0", "vega": "~5.20.0", "vega-embed": "6.19.1", "vega-functions": "5.12.0", "vega-lite": "5.1.1", "vega-parser": "6.1.3", - "visyn_scripts": "^1.1.1" + "visyn_scripts": "^4.1.0" }, "devDependencies": { "@types/d3-selection": "^3.0.2", "@types/d3-transition": "^3.0.1", - "@types/react": "^16.14.6", - "@types/react-dom": "^16.9.5", - "@types/react-router-dom": "^5.1.7", "mkdirp": "0.5.1", "tslint": "~5.20.1", "worker-loader": "^2.0.0" }, + "resolutions": { + "@types/react": "~18.2.0", + "@types/react-dom": "~18.2.0", + "react": "~18.2.0", + "react-dom": "~18.2.0" + }, "browser": { "fs": false, "os": false, diff --git a/requirements.txt b/requirements.txt index e633162..704c3a1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -tdp_core>=17.0.0,<18.0.0 +tdp_publicdb@git+https://github.com/Caleydo/tdp_publicdb.git@v14.0.0#egg=tdp_publicdb +tdp_core>=20.1.0,<21.0.0 \ No newline at end of file diff --git a/src/Cohort.ts b/src/Cohort.ts index c4114c3..6420e29 100644 --- a/src/Cohort.ts +++ b/src/Cohort.ts @@ -1,5 +1,21 @@ -import { IAllFilters, IDType, IDTypeLike, IDTypeManager, IRow, IServerColumn, UniqueIdManager } from 'tdp_core'; -import { ElementProvType, ICohort, ICohortRep, IElement, IElementProvJSONCohort, IProvAttrAndValuesCohort } from './CohortInterfaces'; +/* eslint-disable @typescript-eslint/no-use-before-define */ +import { IDType, IDTypeLike, IDTypeManager } from 'visyn_core/idtype'; +import { IRow, IServerColumn } from 'visyn_core/base'; +import { IAllFilters, UniqueIdManager } from 'tdp_core'; +import { + ECloneFilterTypes, + EElementProvType, + IBloodlineElement, + ICohort, + ICohortClassBasicValues, + ICohortClassDatabaseValues, + ICohortRep, + IElement, + IElementProvJSONCohort, + IInputCohort, + IOutputCohort, + IProvAttrAndValuesCohort, +} from './app/interfaces'; import { createDBCohort, createDBCohortWithDepletionScoreFilter, @@ -17,6 +33,17 @@ import { dataDBCohortWithNumFilter, getCohortData, getCohortSize, + sizeDBCohortDepletionScoreFilter, + sizeDBCohortGeneWithEqualsFilter, + sizeDBCohortGeneWithNumFilter, + sizeDBCohortPanelAnnotationFilter, + sizeDBCohortWithEqualsFilter, + sizeDBCohortWithNumFilter, + updateCohortName, +} from './base/rest'; +import type { Task } from './Tasks'; +import { deepCopy, handleDataLoadError, handleDataSaveError, log, mergeTwoAllFilters } from './util'; +import { ICohortDBDataParams, ICohortDBParams, ICohortDBSizeParams, @@ -36,17 +63,8 @@ import { ICohortRow, IEqualsList, INumRange, - sizeDBCohortDepletionScoreFilter, - sizeDBCohortGeneWithEqualsFilter, - sizeDBCohortGeneWithNumFilter, - sizeDBCohortPanelAnnotationFilter, - sizeDBCohortWithEqualsFilter, - sizeDBCohortWithNumFilter, - updateCohortName, valueListDelimiter, -} from './rest'; -import { mergeTwoAllFilters, Task } from './Tasks'; -import { deepCopy, handleDataLoadError, handleDataSaveError, log } from './util'; +} from './base/interfaces'; type ICreateMethod = ( params: @@ -74,7 +92,7 @@ export async function createCohort( idType: IDTypeLike, idColumn: IServerColumn, filters: IAllFilters, -): Promise { +): Promise { const params: ICohortDBParams = { name: combineLabelsForDB(labelOne, labelTwo), isInitial: isInitial ? 1 : 0, @@ -115,13 +133,13 @@ function getLegacyRangeFilter(parentFilters: IAllFilters, attribute: string, ran } export async function createCohortWithEqualsFilter( - parentCohort: Cohort, + parentCohort: ICohort, labelOne: string, labelTwo: string, attribute: string, numeric: 'true' | 'false', values: Array | Array, -): Promise { +): Promise { const params: ICohortDBWithEqualsFilterParams = { cohortId: parentCohort.dbId, name: combineLabelsForDB(labelOne, labelTwo), @@ -153,13 +171,13 @@ export async function createCohortWithEqualsFilter( } export async function createCohortWithTreatmentFilter( - parentCohort: Cohort, + parentCohort: ICohort, labelOne: string, labelTwo: string, baseAgent: boolean, agent: Array, regimen: number, -): Promise { +): Promise { const params: ICohortDBWithTreatmentFilterParams = { cohortId: parentCohort.dbId, name: combineLabelsForDB(labelOne, labelTwo), @@ -191,12 +209,12 @@ export async function createCohortWithTreatmentFilter( } export async function createCohortWithNumFilter( - parentCohort: Cohort, + parentCohort: ICohort, labelOne: string, labelTwo: string, attribute: string, ranges: Array, -): Promise { +): Promise { const params: ICohortDBWithNumFilterParams = { cohortId: parentCohort.dbId, name: combineLabelsForDB(labelOne, labelTwo), @@ -227,14 +245,14 @@ export async function createCohortWithNumFilter( } export async function createCohortWithGeneNumFilter( - parentCohort: Cohort, + parentCohort: ICohort, labelOne: string, labelTwo: string, table: string, attribute: string, ensg: string, ranges: Array, -): Promise { +): Promise { const params: ICohortDBWithGeneNumFilterParams = { cohortId: parentCohort.dbId, name: combineLabelsForDB(labelOne, labelTwo), @@ -268,7 +286,7 @@ export async function createCohortWithGeneNumFilter( } export async function createCohortWithGeneEqualsFilter( - parentCohort: Cohort, + parentCohort: ICohort, labelOne: string, labelTwo: string, table: string, @@ -276,7 +294,7 @@ export async function createCohortWithGeneEqualsFilter( ensg: string, numeric: 'true' | 'false', values: Array | Array, -): Promise { +): Promise { const params: ICohortDBWithGeneEqualsFilterParams = { cohortId: parentCohort.dbId, name: combineLabelsForDB(labelOne, labelTwo), @@ -311,7 +329,7 @@ export async function createCohortWithGeneEqualsFilter( } export async function createCohortWithDepletionScoreFilter( - parentCohort: Cohort, + parentCohort: ICohort, labelOne: string, labelTwo: string, table: string, @@ -319,7 +337,7 @@ export async function createCohortWithDepletionScoreFilter( ensg: string, depletionscreen: string, ranges: Array, -): Promise { +): Promise { const params: ICohortDBWithDepletionScoreFilterParams = { cohortId: parentCohort.dbId, name: combineLabelsForDB(labelOne, labelTwo), @@ -354,12 +372,12 @@ export async function createCohortWithDepletionScoreFilter( } export async function createCohortWithPanelAnnotationFilter( - parentCohort: Cohort, + parentCohort: ICohort, labelOne: string, labelTwo: string, panel: string, values: Array, -): Promise { +): Promise { const params: ICohortDBWithPanelAnnotationFilterParams = { cohortId: parentCohort.dbId, name: combineLabelsForDB(labelOne, labelTwo), @@ -429,7 +447,7 @@ function splitLabelsFromDB(name: string): { labelOne: string; labelTwo: string } }; } -export function createCohortFromDB(data: ICohortRow, provJSON: IProvAttrAndValuesCohort): Cohort { +export function createCohortFromDB(data: ICohortRow, provJSON: IProvAttrAndValuesCohort): ICohort { // ATTENTION : database != databaseName const labels = splitLabelsFromDB(data.name); const isInitial = data.is_initial === 1; @@ -455,32 +473,6 @@ export function createCohortFromDB(data: ICohortRow, provJSON: IProvAttrAndValue return cht; } -export enum cloneFilterTypes { - none, - equals, - range, - geneScoreRange, - geneScoreEquals, - depletionScoreRange, - panelAnnotation, -} - -export interface ICohortClassBasicValues { - id: string; - dbId: number; - labelOne: string; - labelTwo: string; -} - -export interface ICohortClassDatabaseValues { - database: string; - schema: string; - table: string; - view: string; - idType: IDTypeLike; - idColumn: IServerColumn; -} - export class Cohort implements ICohort { // public from interface public id: string; @@ -497,7 +489,7 @@ export class Cohort implements ICohort { public isInitial: boolean; - public values: Array; + public values: (INumRange[] | IEqualsList)[]; public isClone: boolean; @@ -505,7 +497,7 @@ export class Cohort implements ICohort { private _sizeReference: number; - public usedFilter: cloneFilterTypes; + public usedFilter: ECloneFilterTypes; public usedFilterParams: | ICohortEqualsFilterParams @@ -529,7 +521,7 @@ export class Cohort implements ICohort { private _children: Array; - private _parentCohorts: Array; + private _parentCohorts: ICohort[]; private _filters: IAllFilters; @@ -545,7 +537,7 @@ export class Cohort implements ICohort { constructor( basicValues: ICohortClassBasicValues, - values: Array, + values: (INumRange[] | IEqualsList)[], databaseValues: ICohortClassDatabaseValues, filters: IAllFilters = { normal: {}, lt: {}, lte: {}, gt: {}, gte: {} }, sizeReference: number = null, @@ -634,29 +626,29 @@ export class Cohort implements ICohort { return labelOneHTML; } - public set parents(parents: Array) { + public set parents(parents: IElement[]) { this._parents = parents; this.updateBloodline(); } - public get parents(): Array { + public get parents(): IElement[] { return this._parents; } /** * Returns all parent tasks, which are all the parent elements of this element. */ - public getTaskParents(): Array { + public getTaskParents(): Task[] { return this._parents as Task[]; } /** * Returns all parent cohorts, which are all the grand-parent elements of this element. */ - public getCohortParents(): Array { - const chtParents: Cohort[] = []; + public getCohortParents(): ICohort[] { + const chtParents: ICohort[] = []; for (const p of this._parents) { - chtParents.push(...(p.parents as Cohort[])); + chtParents.push(...(p.parents as ICohort[])); } if (chtParents.length === 0 && !this.isInitial) { @@ -666,32 +658,32 @@ export class Cohort implements ICohort { return chtParents; } - public setCohortParents(chtParents: Array) { + public setCohortParents(chtParents: ICohort[]) { this._parentCohorts = chtParents; } - public set children(children: Array) { + public set children(children: IElement[]) { this._children = children; } - public get children(): Array { + public get children(): IElement[] { return this._children; } /** * Returns all children tasks, which are all the children elements of this element. */ - public getTaskChildren(): Array { + public getTaskChildren(): Task[] { return this._children as Task[]; } /** * Returns all children cohorts, which are all the grand-children elements of this element. */ - public getCohortChildren(): Array { - const chtChildren: Cohort[] = []; + public getCohortChildren(): ICohort[] { + const chtChildren: ICohort[] = []; for (const p of this._children) { - chtChildren.push(...(p.children as Cohort[])); + chtChildren.push(...(p.children as ICohort[])); } return chtChildren; } @@ -785,25 +777,25 @@ export class Cohort implements ICohort { }; try { if (this.isClone) { - if (this.usedFilter === cloneFilterTypes.none) { + if (this.usedFilter === ECloneFilterTypes.none) { return await getCohortSize(params); } - if (this.usedFilter === cloneFilterTypes.equals) { + if (this.usedFilter === ECloneFilterTypes.equals) { return await sizeDBCohortWithEqualsFilter(this.usedFilterParams as ICohortEqualsFilterParams); } - if (this.usedFilter === cloneFilterTypes.range) { + if (this.usedFilter === ECloneFilterTypes.range) { return await sizeDBCohortWithNumFilter(this.usedFilterParams as ICohortNumFilterParams); } - if (this.usedFilter === cloneFilterTypes.geneScoreRange) { + if (this.usedFilter === ECloneFilterTypes.geneScoreRange) { return await sizeDBCohortGeneWithNumFilter(this.usedFilterParams as ICohortGeneNumFilterParams); } - if (this.usedFilter === cloneFilterTypes.geneScoreEquals) { + if (this.usedFilter === ECloneFilterTypes.geneScoreEquals) { return await sizeDBCohortGeneWithEqualsFilter(this.usedFilterParams as ICohortGeneEqualsFilterParams); } - if (this.usedFilter === cloneFilterTypes.depletionScoreRange) { + if (this.usedFilter === ECloneFilterTypes.depletionScoreRange) { return await sizeDBCohortDepletionScoreFilter(this.usedFilterParams as ICohortDepletionScoreFilterParams); } - if (this.usedFilter === cloneFilterTypes.panelAnnotation) { + if (this.usedFilter === ECloneFilterTypes.panelAnnotation) { return await sizeDBCohortPanelAnnotationFilter(this.usedFilterParams as ICohortPanelAnnotationFilterParams); } } else { @@ -812,6 +804,7 @@ export class Cohort implements ICohort { } catch (e) { handleDataLoadError(e); } + return Promise.reject(); } private async _fetchData(): Promise { @@ -820,25 +813,25 @@ export class Cohort implements ICohort { }; try { if (this.isClone) { - if (this.usedFilter === cloneFilterTypes.none) { + if (this.usedFilter === ECloneFilterTypes.none) { return await getCohortData(params); } - if (this.usedFilter === cloneFilterTypes.equals) { + if (this.usedFilter === ECloneFilterTypes.equals) { return await dataDBCohortWithEqualsFilter(this.usedFilterParams as ICohortEqualsFilterParams); } - if (this.usedFilter === cloneFilterTypes.range) { + if (this.usedFilter === ECloneFilterTypes.range) { return await dataDBCohortWithNumFilter(this.usedFilterParams as ICohortNumFilterParams); } - if (this.usedFilter === cloneFilterTypes.geneScoreRange) { + if (this.usedFilter === ECloneFilterTypes.geneScoreRange) { return await dataDBCohortGeneWithNumFilter(this.usedFilterParams as ICohortGeneNumFilterParams); } - if (this.usedFilter === cloneFilterTypes.geneScoreEquals) { + if (this.usedFilter === ECloneFilterTypes.geneScoreEquals) { return await dataDBCohortGeneWithEqualsFilter(this.usedFilterParams as ICohortGeneEqualsFilterParams); } - if (this.usedFilter === cloneFilterTypes.depletionScoreRange) { + if (this.usedFilter === ECloneFilterTypes.depletionScoreRange) { return await dataDBCohortDepletionScoreFilter(this.usedFilterParams as ICohortDepletionScoreFilterParams); } - if (this.usedFilter === cloneFilterTypes.panelAnnotation) { + if (this.usedFilter === ECloneFilterTypes.panelAnnotation) { return await dataDBCohortPanelAnnotationFilter(this.usedFilterParams as ICohortPanelAnnotationFilterParams); } } else { @@ -849,11 +842,12 @@ export class Cohort implements ICohort { } catch (e) { handleDataLoadError(e); } + return Promise.reject(); } // filter method and params for the function clone( - usedFilter: cloneFilterTypes, + usedFilter: ECloneFilterTypes, filterParams: | ICohortEqualsFilterParams | ICohortNumFilterParams @@ -861,7 +855,7 @@ export class Cohort implements ICohort { | ICohortGeneEqualsFilterParams | ICohortDepletionScoreFilterParams | ICohortPanelAnnotationFilterParams, - ): Cohort { + ): ICohort { const clone = new Cohort( { id: `${this.id}-clone#${UniqueIdManager.getInstance().uniqueId('cht:cohort')}`, dbId: this.dbId, labelOne: this.labelOne, labelTwo: this.labelTwo }, this.values, @@ -920,7 +914,7 @@ export class Cohort implements ICohort { public toProvenanceJSON(): IElementProvJSONCohort { return { id: this.id, - type: ElementProvType.Cohort, + type: EElementProvType.Cohort, label: this.label, parent: this._parents.map((elem) => elem.id), children: this._children.map((elem) => elem.id), @@ -937,16 +931,23 @@ export class Cohort implements ICohort { } } -export interface IBloodlineElement { - obj: IElement; - elemType: string; - label: string; - size: number; +// This class is currently unused because it is covered by typecasting the `Cohort` object into `IInputCohort` and adding the missing property in a hacky way +// TODO the `Cohort` object should be transformed/cloned into an `InputCohort`. Otherwise we can remove this class +export class InputCohort extends Cohort implements IInputCohort { + outputCohorts: IOutputCohort[] = []; +} + +// This class is currently unused because it is covered by typecasting the `Cohort` object into `IOutputCohort` and adding the missing property in a hacky way +// TODO the `Cohort` object should be transformed/cloned into an `OutputCohort`. Otherwise we can remove this class +export class OutputCohort extends Cohort implements IOutputCohort { + public isLastOutputCohort = false; // used to add a paddding between outputcohorts of different input cohorts + + public isFirstOutputCohort = false; // used to add a paddding between outputcohorts of different input cohorts } export const EMPTY_COHORT_ID = '--EMPTY--'; -export function getEmptyCohort(parent: Cohort) { - const cht = new Cohort({ id: EMPTY_COHORT_ID, dbId: NaN, labelOne: 'Empty', labelTwo: '' }, null, { +export function getEmptyCohort(parent: ICohort) { + const cht: ICohort = new Cohort({ id: EMPTY_COHORT_ID, dbId: NaN, labelOne: 'Empty', labelTwo: '' }, null, { database: null, schema: null, table: null, @@ -959,8 +960,8 @@ export function getEmptyCohort(parent: Cohort) { } export const LOADER_COHORT_ID = '--LOADING--'; -export function getLoaderCohort(parent: Cohort) { - const cht = new Cohort({ id: LOADER_COHORT_ID, dbId: NaN, labelOne: 'Loading', labelTwo: '' }, null, { +export function getLoaderCohort(parent: ICohort) { + const cht: ICohort = new Cohort({ id: LOADER_COHORT_ID, dbId: NaN, labelOne: 'Loading', labelTwo: '' }, null, { database: null, schema: null, table: null, @@ -972,10 +973,10 @@ export function getLoaderCohort(parent: Cohort) { return cht; } -export function getCohortLabel(cht: Cohort) { +export function getCohortLabel(cht: ICohort) { return cht.label; } -export function getCohortLabels(cohorts: Cohort[]) { +export function getCohortLabels(cohorts: ICohort[]) { return cohorts.map((cht) => getCohortLabel(cht)); } diff --git a/src/CohortContext.ts b/src/CohortContext.ts new file mode 100644 index 0000000..c1837bd --- /dev/null +++ b/src/CohortContext.ts @@ -0,0 +1,15 @@ +import type { ICohort } from './app/interfaces'; +import type { CohortOverview } from './Overview/CohortOverview'; +import type Taskview from './Taskview/Taskview'; + +export interface ICohortContext { + cohortOverview: CohortOverview; + taskview: Taskview; + referenceCohort: ICohort; +} + +export const CohortContext: ICohortContext = { + cohortOverview: null, + taskview: null, + referenceCohort: null, +}; diff --git a/src/CohortRepresentations.ts b/src/CohortRepresentations.ts index ba69ada..a277140 100644 --- a/src/CohortRepresentations.ts +++ b/src/CohortRepresentations.ts @@ -1,11 +1,10 @@ -import {hsl} from 'd3v7'; +import { hsl } from 'd3v7'; import tippy from 'tippy.js'; -import { Cohort } from './Cohort'; -import { IElement, IRectCohortRep } from './CohortInterfaces'; -import { getRootCohort } from './cohortview'; +import { IBloodlineElement, ICohort, IElement, IRectCohortRep } from './app/interfaces'; +import { CohortContext } from './CohortContext'; import { log } from './util'; -import { CohortRemoveEvent, CohortSelectionEvent } from './utilCustomEvents'; -import { labelFromFilter } from './utilLabels'; +import { CohortRemoveEvent, CohortSelectionEvent } from './base/events'; +import { labelFromFilter } from './utils/labels'; export class RectCohortRep implements IRectCohortRep { id: string; @@ -22,11 +21,11 @@ export class RectCohortRep implements IRectCohortRep { private _width: number; - private _cohort: Cohort; + private _cohort: ICohort; private _isSelected: boolean; - private _bloodline: Array; + private _bloodline: any[]; private _bloodlinePaths: SVGPathElement[]; @@ -36,7 +35,7 @@ export class RectCohortRep implements IRectCohortRep { private _refSize: number; - constructor(private cohort: Cohort, height: number, width: number) { + constructor(private cohort: ICohort, height: number, width: number) { this.id = cohort.id; this.labelOne = cohort.labelOne; this.labelTwo = cohort.labelTwo; @@ -137,7 +136,7 @@ export class RectCohortRep implements IRectCohortRep { container.addEventListener('mouseenter', (event) => { event.stopPropagation(); // remove icon (=trash can) - const isRoot = this._cohort.dbId === getRootCohort().dbId; + const isRoot = this._cohort.dbId === CohortContext.referenceCohort?.dbId; const isPreview = this._representation.classList.contains('preview'); // onyl if it is not a preview if (!isPreview) { @@ -188,10 +187,10 @@ export class RectCohortRep implements IRectCohortRep { delConfirm = modal.querySelector('.confirm-delete'); // add click event to delete button - delConfirm.addEventListener('click', (event) => { + delConfirm.addEventListener('click', (event2) => { // dispatch event to remove cohort and its children container.dispatchEvent(new CohortRemoveEvent(this.cohort)); - event.stopPropagation(); + event2.stopPropagation(); // hide modal ($('#deleteModal') as any).modal('hide'); }); @@ -300,7 +299,8 @@ export class RectCohortRep implements IRectCohortRep { this._representation.style.backgroundColor = color; this._repClone.style.backgroundColor = color; // font color = white if color is too dark - if (color !== null && color !== 'transparent' && hsl(color).l < 0.6) { //transparent has lightness of zero + if (color !== null && color !== 'transparent' && hsl(color).l < 0.6) { + // transparent has lightness of zero this._representation.style.color = 'white'; this._repClone.style.color = 'white'; this._removeButton.style.color = 'white'; @@ -496,7 +496,7 @@ export class RectCohortRep implements IRectCohortRep { const cohort = this._bloodline[i - 1]; // TODO labels // const valueLabel = cohort.obj.labelTwo.replace(htmlLte,'<=').replace(htmlLt,'<'); - const cohortObj = cohort.obj as Cohort; + const cohortObj = cohort.obj as ICohort; ttInfo.chtName = cohortObj.label; ttInfo.chtSize = cohort.size; ttInfo.prevSize = previousSize; @@ -507,9 +507,9 @@ export class RectCohortRep implements IRectCohortRep { log.debug('cohortValues: ', cohortValues); const detailedLabelArray = []; const labels = cohortObj.labelOne.split(', '); - for (let i = 0; i < cohortValues.length; i++) { - const val = cohortValues[i]; - const label = labels[i]; + for (let j = 0; j < cohortValues.length; j++) { + const val = cohortValues[j]; + const label = labels[j]; let labelpart = ''; if (Array.isArray(val)) { labelpart = val.map((a) => labelFromFilter(a, label)).join(' / '); @@ -517,7 +517,7 @@ export class RectCohortRep implements IRectCohortRep { labelpart = labelFromFilter(val, label); } detailedLabelArray.push(labelpart); - ttInfo.attr.push({ name: attrLabel[i], value: labelpart }); + ttInfo.attr.push({ name: attrLabel[j], value: labelpart }); } const detailedLabel = detailedLabelArray.join(', '); const valueLabel = detailedLabel.replace(htmlLte, '<=').replace(htmlLt, '<').replace(htmlGte, '>=').replace(htmlGt, '>'); @@ -536,7 +536,7 @@ export class RectCohortRep implements IRectCohortRep { } else { const cohort = this._bloodline[0]; const ttInfo = { chtName: '', chtSize: 0, prevSize: 0, percentage: 0, attr: [] }; - const cohortObj = cohort.obj as Cohort; + const cohortObj = cohort.obj as ICohort; ttInfo.chtName = cohortObj.label; ttInfo.chtSize = cohort.size; ttInfo.prevSize = previousSize; @@ -568,21 +568,22 @@ export class RectCohortRep implements IRectCohortRep { // cohort info // name - const currChtInfo = ttInfo[ttInfo.length - 1]; - const chtName = document.createElement('div'); - chtName.innerHTML = currChtInfo.chtName; - chtName.style.fontWeight = 'bold'; - // values - const chtValues = document.createElement('div'); - for (const a of currChtInfo.attr) { - const currAttr = document.createElement('div'); - currAttr.innerHTML = `${a.name}: ${a.value}`; - currAttr.style.paddingLeft = '15px'; - chtValues.appendChild(currAttr); + { + const currChtInfo = ttInfo[ttInfo.length - 1]; + const chtName = document.createElement('div'); + chtName.innerHTML = currChtInfo.chtName; + chtName.style.fontWeight = 'bold'; + // values + const chtValues = document.createElement('div'); + for (const a of currChtInfo.attr) { + const currAttr = document.createElement('div'); + currAttr.innerHTML = `${a.name}: ${a.value}`; + currAttr.style.paddingLeft = '15px'; + chtValues.appendChild(currAttr); + } + ctrCohort.appendChild(chtName); + ctrCohort.appendChild(chtValues); } - ctrCohort.appendChild(chtName); - ctrCohort.appendChild(chtValues); - if (!root) { // provenance // label for provenance diff --git a/src/OnboardingManager.ts b/src/OnboardingManager.ts index 81558ce..e3162a2 100644 --- a/src/OnboardingManager.ts +++ b/src/OnboardingManager.ts @@ -1,5 +1,5 @@ import * as loMerge from 'lodash.merge'; -import tippy, { hideAll, Props, Instance as TippyInstance } from 'tippy.js'; +import tippy, { Props, Instance as TippyInstance } from 'tippy.js'; import { CONFIG_ONBOARDING } from './config/onboarding'; import { log, hasCookie } from './util'; @@ -17,7 +17,7 @@ export class OnboardingManager { const tipConfig = CONFIG_ONBOARDING.tooltips[tipId]; let tip; if (tipConfig) { - this.tooltips.forEach((tip) => tip.clearDelayTimeouts()); + this.tooltips.forEach((ttip) => ttip.clearDelayTimeouts()); const cookieID = `${tipId}_onboarded`; const showOnCreate = !hasCookie(cookieID) || forceShow; // show if there is no cookie tip = tippy(elem, { @@ -26,6 +26,7 @@ export class OnboardingManager { showOnCreate, }); this.tooltips.set(tipId, tip); + // eslint-disable-next-line @typescript-eslint/no-use-before-define setOnboardingCookie(cookieID); } else { log.warn('No config for tooltip', tipId, 'Skip tooltip creation'); diff --git a/src/Overview/CohortOverview.ts b/src/Overview/CohortOverview.ts index a7e2e1e..aa79261 100644 --- a/src/Overview/CohortOverview.ts +++ b/src/Overview/CohortOverview.ts @@ -1,15 +1,25 @@ import { IObjectRef, ObjectRefUtils, ProvenanceGraph, UniqueIdManager, IDatabaseViewDesc } from 'tdp_core'; import tippy from 'tippy.js'; -import { CohortApp } from '../app'; +import type { CoralApp } from '../app/CoralApp'; import { Cohort, createCohortFromDB } from '../Cohort'; -import { ElementProvType, IElement, IElementProvJSON, IOverviewLayout, IRectCohortRep, IRectTaskRep, ITask, ITaskParams, TaskType } from '../CohortInterfaces'; +import { + EElementProvType, + ICohort, + IElement, + IElementProvJSON, + IOverviewLayout, + IRectCohortRep, + IRectTaskRep, + ITask, + ITaskParams, + TaskType, +} from '../app/interfaces'; import { RectCohortRep } from '../CohortRepresentations'; -import { IAttribute } from '../data/Attribute'; -import { addOverviewCohortAction, removeOverviewCohortAction } from '../Provenance/CohortEV'; -import { getDBCohortData } from '../rest'; +import { getDBCohortData } from '../base/rest'; import { RectTaskRep } from '../TaskRepresentations'; import { createTaskFromProvJSON, Task, TaskFilter, TaskSplit } from '../Tasks'; -import { deepCopy, log, ScrollLinker } from '../util'; +import { deepCopy, log } from '../util'; +import { ScrollLinker } from '../utils/ScrollLinker'; import { CohortRemoveEvent, CohortSelectionEvent, @@ -19,12 +29,14 @@ import { PreviewChangeEvent, TaskRemoveEvent, TASK_REMOVE_EVENT_TYPE, -} from '../utilCustomEvents'; -import { niceName } from '../utilLabels'; +} from '../base/events'; +import { niceName } from '../utils/labels'; import { RectangleLayout } from './OverviewLayout'; +import { IAttribute } from '../data/IAttribute'; +import { addOverviewCohortAction, removeOverviewCohortAction } from '../Provenance/CohortEV'; export class CohortOverview { - private root: Cohort; + private root: ICohort; private rootDBid: number; @@ -62,18 +74,18 @@ export class CohortOverview { public readonly ref: IObjectRef; - public readonly appRef: IObjectRef; + public readonly appRef: IObjectRef; private refName = 'CohortApp-Overview'; - private _reference: Cohort; + private _reference: ICohort; constructor( private parent: HTMLDivElement, graph: ProvenanceGraph, - ref: IObjectRef, + ref: IObjectRef, layout: IOverviewLayout, - root: Cohort, + root: ICohort, viewDescr: IDatabaseViewDesc, ) { this.root = root; @@ -235,7 +247,7 @@ export class CohortOverview { public executeTask(taskParam: ITaskParams, attributes: IAttribute[], addToTaskHistory = true): Task { log.debug('executeTask: ', taskParam); let validType = false; - const parentCohort: Cohort = taskParam.inputCohorts[0] as Cohort; + const parentCohort: ICohort = taskParam.inputCohorts[0]; let task: ITask; if (taskParam.type === TaskType.Filter) { validType = true; @@ -416,7 +428,7 @@ export class CohortOverview { } // create missing Cohorts - const jsonCohorts = jsonElementsToCreate.filter((elem) => elem.type === ElementProvType.Cohort); + const jsonCohorts = jsonElementsToCreate.filter((elem) => elem.type === EElementProvType.Cohort); const cohortIDs: number[] = jsonCohorts.map((elem) => Number(elem.id)); // get cohort DB data const chtSizes = []; @@ -447,7 +459,7 @@ export class CohortOverview { // console.log('root element found (AFTER): ', foundRoot); // create missing Tasks - const jsonTasks = jsonElementsToCreate.filter((elem) => elem.type !== ElementProvType.Cohort); + const jsonTasks = jsonElementsToCreate.filter((elem) => elem.type !== EElementProvType.Cohort); for (const jsonT of jsonTasks) { const newTask = createTaskFromProvJSON(jsonT); provElements.push(newTask); diff --git a/src/Overview/OverviewLayout.ts b/src/Overview/OverviewLayout.ts index 8c7d9b9..717fc5f 100644 --- a/src/Overview/OverviewLayout.ts +++ b/src/Overview/OverviewLayout.ts @@ -1,4 +1,4 @@ -import { ICohort, IElement, IOverviewLayout, IRectLayout, ITask } from '../CohortInterfaces'; +import { ICohort, IElement, IOverviewLayout, IRectLayout, ITask } from '../app/interfaces'; import { Task } from '../Tasks'; import { deepCopy, log } from '../util'; diff --git a/src/Provenance/CohortEV.ts b/src/Provenance/CohortEV.ts index e862734..f2200fe 100644 --- a/src/Provenance/CohortEV.ts +++ b/src/Provenance/CohortEV.ts @@ -1,7 +1,8 @@ +/* eslint-disable @typescript-eslint/no-use-before-define */ import { ActionMetaData, ActionUtils, ICmdResult, IObjectRef, ObjectRefUtils } from 'tdp_core'; -import { CohortApp } from '../app'; -import { IElementProvJSON } from '../CohortInterfaces'; -import { CohortOverview } from '../Overview/CohortOverview'; +import type { CoralApp } from '../app/CoralApp'; +import { IElementProvJSON } from '../app/interfaces'; +import type { CohortOverview } from '../Overview/CohortOverview'; import { log } from '../util'; /** ********************************************* @@ -13,7 +14,7 @@ import { log } from '../util'; // ---------------------------- export function addOverviewCohortAction( provider: IObjectRef, - providerApp: IObjectRef, + providerApp: IObjectRef, newDataset: IElementProvJSON[], oldDataset: IElementProvJSON[], ) { @@ -33,7 +34,7 @@ export function addOverviewCohortAction( export async function addOverviewCohortImpl(inputs: IObjectRef[], parameter: any): Promise { log.debug('addOverviewCohortImpl', { inputs, parameter }); // get app CohortApp - const app: CohortApp = await inputs[1].v; + const app: CoralApp = await inputs[1].v; // get the overview of CohortApp const ovApp = app.getAppOverview(); if (ovApp) { @@ -48,7 +49,7 @@ export async function addOverviewCohortImpl(inputs: IObjectRef[], parameter }; } -function setChtCounter(parameter: any, app: CohortApp) { +function setChtCounter(parameter: any, app: CoralApp) { const numbers = parameter.newDataset .filter((e) => e.type === 'Cohort') .map((e) => @@ -70,7 +71,7 @@ function setChtCounter(parameter: any, app: CohortApp) { // ---------------------------- export function removeOverviewCohortAction( provider: IObjectRef, - providerApp: IObjectRef, + providerApp: IObjectRef, newDataset: IElementProvJSON[], oldDataset: IElementProvJSON[], ) { @@ -90,7 +91,7 @@ export function removeOverviewCohortAction( export async function removeOverviewCohortImpl(inputs: IObjectRef[], parameter: any): Promise { log.debug('removeOverviewCohortImpl', { inputs, parameter }); // get app CohortApp - const app: CohortApp = await inputs[1].v; + const app: CoralApp = await inputs[1].v; // get the overview of CohortApp const ovApp = app.getAppOverview(); if (ovApp) { diff --git a/src/Provenance/General.ts b/src/Provenance/General.ts index 7d075e8..4a5429a 100644 --- a/src/Provenance/General.ts +++ b/src/Provenance/General.ts @@ -1,8 +1,8 @@ import { ActionMetaData, ActionUtils, ICmdResult, IObjectRef, ObjectRefUtils } from 'tdp_core'; -import { CohortApp } from '../app'; -import { IElementProvJSON, IElementProvJSONCohort } from '../CohortInterfaces'; +import type { CoralApp } from '../app/CoralApp'; +import { IElementProvJSON, IElementProvJSONCohort } from '../app/interfaces'; import { log } from '../util'; -import { IEntitySourceConfig } from '../utilIdTypes'; +import { IEntitySourceConfig } from '../config/entities'; /** **************************** ---------- GENERAL ---------- @@ -11,11 +11,12 @@ import { IEntitySourceConfig } from '../utilIdTypes'; // ---------------------------- // ---- DATASET --------------- // ---------------------------- -export function setDatasetAction(provider: IObjectRef, newDataset: IDatasetDesc, oldDataset: IDatasetDesc) { +export function setDatasetAction(provider: IObjectRef, newDataset: IDatasetDesc, oldDataset: IDatasetDesc) { log.debug('Create setDataset Action'); return ActionUtils.action( ActionMetaData.actionMeta('Change Dataset', ObjectRefUtils.category.data, ObjectRefUtils.operation.update), 'chtSetDataset', + // eslint-disable-next-line @typescript-eslint/no-use-before-define setDatasetImpl, [provider], { @@ -25,9 +26,9 @@ export function setDatasetAction(provider: IObjectRef, newDataset: ID ); } -export async function setDatasetImpl(inputs: IObjectRef[], parameter: any): Promise { +export async function setDatasetImpl(inputs: IObjectRef[], parameter: any): Promise { log.debug('setDataset impl', parameter.oldDataset, parameter.newDataset); - const app: CohortApp = await inputs[0].v; + const app: CoralApp = await inputs[0].v; await app.setDataset(parameter.newDataset); return { inverse: setDatasetAction(inputs[0], parameter.oldDataset, parameter.newDataset), diff --git a/src/TaskRepresentations.ts b/src/TaskRepresentations.ts index 10d4bd3..3dfa282 100644 --- a/src/TaskRepresentations.ts +++ b/src/TaskRepresentations.ts @@ -1,6 +1,6 @@ -import { IRectTaskRep } from './CohortInterfaces'; +import { IRectTaskRep } from './app/interfaces'; import { Task } from './Tasks'; -import { TaskRemoveEvent } from './utilCustomEvents'; +import { TaskRemoveEvent } from './base/events'; export class RectTaskRep implements IRectTaskRep { id: string; @@ -98,10 +98,10 @@ export class RectTaskRep implements IRectTaskRep { delConfirm = modal.querySelector('.confirm-delete'); // add click event to delete button - delConfirm.addEventListener('click', (event) => { + delConfirm.addEventListener('click', (event2) => { // dispatch event to remove task and its children container.dispatchEvent(new TaskRemoveEvent(this.task)); - event.stopPropagation(); + event2.stopPropagation(); // hide modal ($('#deleteModal') as any).modal('hide'); }); diff --git a/src/Tasks.ts b/src/Tasks.ts index ba039f3..9fae40f 100644 --- a/src/Tasks.ts +++ b/src/Tasks.ts @@ -1,7 +1,53 @@ -import { IAllFilters, IParams } from 'tdp_core'; -import { ElementProvType, IElement, IElementProvJSON, IElementProvJSONTask, ITask, ITaskRep, TaskType } from './CohortInterfaces'; -import { IAttribute, toAttribute } from './data/Attribute'; -import { deepCopy, log } from './util'; +import type { IServerColumn } from 'visyn_core/base'; +import { log } from './util'; +import { EElementProvType, IElement, IElementProvJSON, IElementProvJSONTask, ITask, ITaskRep, TaskType } from './app/interfaces'; +import { GeneScoreAttribute, PanelScoreAttribute, ServerColumnAttribute, SpecialAttribute } from './data/Attribute'; +import type { IAttribute, IOption, IScoreOption, IServerColumnOption } from './data/IAttribute'; +import type { ISpecialAttribute } from './data/ISpecialAttribute'; + +export interface ISpecialOption extends IServerColumnOption { + optionData: { + serverColumn: IServerColumn; + sAttrId: string; + attrOption: string; + spAttribute: ISpecialAttribute; + }; +} + +export function toAttribute(option: IOption, currentDB, currentView): IAttribute { + if (option.optionType === 'dbc') { + if (option.optionData && (option as ISpecialOption).optionData.spAttribute) { + // Create Special Attribtues + // if (option.optionData.spA === 'treatment') { + log.debug('create special Attribute: ', option.optionId); + log.debug('special Attribute object: ', option.optionData.spAttribute); + return new SpecialAttribute( + option.optionId, + currentView, + currentDB, + (option as ISpecialOption).optionData.spAttribute, + (option as ISpecialOption).optionData.attrOption, + ); + } + // Create Attribute + return new ServerColumnAttribute(option.optionId, currentView, currentDB, (option as IServerColumnOption).optionData.serverColumn); + } + // Create ScoreAttribute + if (option.optionType === 'gene') { + return new GeneScoreAttribute( + option.optionId, + option.optionText, + currentView, + currentDB, + (option as IScoreOption).optionData.type, + (option as IScoreOption).optionData.subType, + ); + } + if (option.optionType === 'panel') { + return new PanelScoreAttribute(option.optionId, currentView, currentDB, 'categorical'); + } + return null; +} export abstract class Task implements ITask { id: string; @@ -42,7 +88,7 @@ export class TaskFilter extends Task { public toProvenanceJSON(): IElementProvJSONTask { return { id: this.id, - type: ElementProvType.TaskFilter, + type: EElementProvType.TaskFilter, label: this.label, parent: this.parents.map((elem) => elem.id), children: this.children.map((elem) => elem.id), @@ -62,7 +108,7 @@ export class TaskSplit extends Task { public toProvenanceJSON(): IElementProvJSONTask { return { id: this.id, - type: ElementProvType.TaskSplit, + type: EElementProvType.TaskSplit, label: this.label, parent: this.parents.map((elem) => elem.id), children: this.children.map((elem) => elem.id), @@ -79,99 +125,8 @@ export function createTaskFromProvJSON(config: IElementProvJSON): Task { return toAttribute(elem.option, elem.currentDB, elem.currentView); }); - if (config.type === ElementProvType.TaskFilter) { + if (config.type === EElementProvType.TaskFilter) { return new TaskFilter(config.id, config.label, attributes); } return new TaskSplit(config.id, config.label, attributes); } - -function mergerAllFilterPart(filterType: FilterType, existingFilter: IParams, newFilter: IParams): IParams { - let mergedFilter = deepCopy(existingFilter); - // const currType : FilterType = FilterType.normal; - let filterContradiction = false; - // go through all attribuets of the new filter - for (const attr in newFilter) { - // check if attribute exists in the new filter - if (Object.prototype.hasOwnProperty.call(newFilter, attr)) { - // check if attribute exists in the existing filter - if (Object.prototype.hasOwnProperty.call(existingFilter, attr)) { - const newVal = newFilter[attr]; // current value for attribute - const existVal = existingFilter[attr]; // current value for attribute - - if (filterType === FilterType.normal) { - // convert newVal to an array of values - const newValArray = Array.isArray(newVal) ? (newVal as string[] | number[] | boolean[]) : new Array(newVal as string | number | boolean); - // convert existVal to an array of values - const existValArray = Array.isArray(existVal) ? (existVal as string[] | number[] | boolean[]) : new Array(existVal as string | number | boolean); - // if all new values are part of the existing values, then the filter is OK - for (const nv of newValArray) { - if (!existValArray.includes(nv)) { - filterContradiction = true; - } - } - // no filter contradiction -> new filter values can be used - if (!filterContradiction) { - // outside of for-loop - mergedFilter[attr] = newFilter[attr]; - } - } else if (filterType === FilterType.lt || filterType === FilterType.lte) { - // smaller is OK - if (newVal <= existVal) { - mergedFilter[attr] = newFilter[attr]; - } else { - filterContradiction = true; - } - } else if (filterType === FilterType.gt || filterType === FilterType.gte) { - // bigger is OK - if (newVal >= existVal) { - mergedFilter[attr] = newFilter[attr]; - } else { - filterContradiction = true; - } - } - } else { - // the new filter attribute is not existing -> add to the resulting filter - mergedFilter[attr] = newFilter[attr]; - } - } - } - - if (filterContradiction) { - mergedFilter = null; - } - log.debug('Filter Contradiction: ', filterContradiction); - return mergedFilter; -} - -export function mergeTwoAllFilters(existingFilter: IAllFilters, newFilter: IAllFilters): IAllFilters { - let mergerAllFilter: IAllFilters = null; - if (existingFilter !== null) { - const normal: IParams = mergerAllFilterPart(FilterType.normal, existingFilter.normal, newFilter.normal); - const lt: IParams = mergerAllFilterPart(FilterType.lt, existingFilter.lt, newFilter.lt); - const lte: IParams = mergerAllFilterPart(FilterType.lte, existingFilter.lte, newFilter.lte); - const gt: IParams = mergerAllFilterPart(FilterType.gt, existingFilter.gt, newFilter.gt); - const gte: IParams = mergerAllFilterPart(FilterType.gte, existingFilter.gte, newFilter.gte); - - // if the filters are all !== null, that means there is no filter contradiction -> set all filters of mergerAllFilter - // otherwise the mergerAllFilter stays null - if (normal !== null && lte !== null && lte !== null && gt !== null && gte !== null) { - mergerAllFilter = { - normal, - lt, - lte, - gt, - gte, - }; - } - } - - return mergerAllFilter; -} - -enum FilterType { - normal, - lt, - lte, - gt, - gte, -} diff --git a/src/Taskview/SearchBar.ts b/src/Taskview/SearchBar.ts index 1f67052..b86a0c0 100644 --- a/src/Taskview/SearchBar.ts +++ b/src/Taskview/SearchBar.ts @@ -1,11 +1,14 @@ -import {select} from 'd3v7'; -import {IdTextPair, IServerColumn, RestBaseUtils} from 'tdp_core'; -import {dataTypes, depletion, IDataSubtypeConfig, IDataTypeConfig} from 'tdp_publicdb'; -import {colors} from '../colors'; -import {ScoreType} from '../data/Attribute'; -import {checkSpecialAttribute, ISpecialAttribute} from '../data/SpecialAttribute'; -import {deepCopy, getAnimatedLoadingText, log} from '../util'; -import {niceName} from '../utilLabels'; +import { select } from 'd3v7'; +import { IServerColumn } from 'visyn_core/base'; +import { IdTextPair, RestBaseUtils } from 'tdp_core'; +import { dataTypes, depletion, IDataSubtypeConfig, IDataTypeConfig } from 'tdp_publicdb'; +import { colors } from '../config/colors'; +import { deepCopy, getAnimatedLoadingText, log } from '../util'; +import { niceName } from '../utils/labels'; +import { IOption, IPanelOption, ISearchBarGroup, IServerColumnOption, OptionType } from '../data/IAttribute'; +import { ISpecialOption } from '../Tasks'; +import type { ISpecialAttribute } from '../data/ISpecialAttribute'; +import { checkSpecialAttribute } from '../data/SpecialAttribute'; export class SearchBar { private _container: HTMLDivElement; @@ -392,7 +395,7 @@ export class SearchBar { }; switch (type) { - case 'dbc': + case 'dbc': { const spAttr: ISpecialAttribute = checkSpecialAttribute(option.optionId); if (spAttr) { (option as ISpecialOption).optionData = { @@ -406,6 +409,7 @@ export class SearchBar { } break; + } case 'gene': // Nothing to do here, added in clickHandler break; @@ -415,6 +419,8 @@ export class SearchBar { species: data.species, }; break; + default: + break; } return option; @@ -919,17 +925,19 @@ export class SearchBar { .enter() .append('div') .attr('class', 'detail-info-option option-element') - .attr('data-optid', (d: IDataSubtypeConfig) => { - return this._composeGeneDataTypeOptId(optionId, d.id); + .attr('data-optid', (v: IDataSubtypeConfig) => { + return this._composeGeneDataTypeOptId(optionId, v.id); }) - .classed('option-selected', (d: IDataSubtypeConfig) => { - return badgeIds.indexOf(this._composeGeneDataTypeOptId(optionId, d.id)) !== -1; + .classed('option-selected', (v: IDataSubtypeConfig) => { + return badgeIds.indexOf(this._composeGeneDataTypeOptId(optionId, v.id)) !== -1; }) - .html((d: IDataSubtypeConfig) => d.name) - .on('click', (event, d: IDataSubtypeConfig) => { - const badgeName = this._composeGeneDataTypeName(data.optionText, d.name); + .html((v: IDataSubtypeConfig) => v.name) + .on('click', (event, v: IDataSubtypeConfig) => { + // merge subtype with the with d as the d.name is only available in the d variable + const dataSubType = { ...d, ...v }; + const badgeName = this._composeGeneDataTypeName(data.optionText, dataSubType.name); const badgeData = deepCopy(data); - badgeData.optionData = { subType: d, type: (d as any).dataTypeId }; + badgeData.optionData = { subType: dataSubType, type: (dataSubType as any).dataTypeId }; this._clickHandlerDetail(data, badgeData, badgeName, event as MouseEvent, event.currentTarget as HTMLElement); // indicate an change in the options this._container.dispatchEvent(new CustomEvent('optionchange')); @@ -952,8 +960,7 @@ export class SearchBar { const detailText = document.createElement('p'); detailText.classList.add('option-element'); detail.appendChild(detailText); - detailText.innerHTML = - `ID: ${option.optionId}
` + `Description: ${option.optionData.description}`; + detailText.innerHTML = `ID: ${option.optionId}
Description: ${option.optionData.description}`; return detail; } @@ -1085,49 +1092,3 @@ export class SearchBar { this._setPlaceholder(); } } - -export interface ISearchBarGroup { - groupLabel: string; - data: Array; -} - -export type OptionType = 'dbc' | 'gene' | 'panel'; - -export interface IOption { - // id: string; - optionId: string; // e.g. gender or ensg00000141510 - optionType: OptionType; // e.g. dbc or gene - optionText: string; // e.g. Gender or TP53 - optionData?: { - [key: string]: any; // keys are always strings, so we just specify it to be key/value pairs with values of any type - }; -} - -export interface IPanelOption extends IOption { - optionData: { - description: string; // e.g. "Cancer Cell Line Encyclopedia" - species: string; // e.g. human - }; -} - -export interface IScoreOption extends IOption { - optionData: { - type: ScoreType; // id of = IDataTypeConfig; - subType: IDataSubtypeConfig; - }; -} - -export interface IServerColumnOption extends IOption { - optionData: { - serverColumn: IServerColumn; - }; -} - -export interface ISpecialOption extends IServerColumnOption { - optionData: { - serverColumn: IServerColumn; - sAttrId: string; - attrOption: string; - spAttribute: ISpecialAttribute; - }; -} diff --git a/src/Taskview/SearchColumn.ts b/src/Taskview/SearchColumn.ts index c6c4b69..43b976d 100644 --- a/src/Taskview/SearchColumn.ts +++ b/src/Taskview/SearchColumn.ts @@ -1,14 +1,15 @@ -import {select} from 'd3v7'; +import { select } from 'd3v7'; import * as $ from 'jquery'; import tippy from 'tippy.js'; -import { Cohort } from '../Cohort'; -import { IAttribute, toAttribute } from '../data/Attribute'; +import type { ICohort } from '../app/interfaces'; +import { IAttribute } from '../data/IAttribute'; +import { toAttribute } from '../Tasks'; import searchHtml from '../templates/SearchColumn.html'; // webpack imports html to variable import { log } from '../util'; import { SearchBar } from './SearchBar'; import { ATask, TaskCloseEvent, TASK_CLOSE_EVENT_TYPE } from './tasks/ATask'; import { TASKLIST } from './tasks/TaskList'; -import Taskview from './Taskview'; +import type Taskview from './Taskview'; export default class SearchColumn { private $searchColumn: HTMLDivElement; @@ -19,13 +20,13 @@ export default class SearchColumn { private searchBar: SearchBar; - private refCohort: Cohort; + private refCohort: ICohort; private $ColumnHeader: HTMLDivElement; activeTask: ATask; - constructor($container: HTMLDivElement, private referenceCht: Cohort, private taskview: Taskview) { + constructor($container: HTMLDivElement, private referenceCht: ICohort, private taskview: Taskview) { $container.insertAdjacentHTML('beforeend', searchHtml); // faster than innerHTML (https://developer.mozilla.org/de/docs/Web/API/Element/insertAdjacentHTML) this.$searchColumn = $container.firstChild as HTMLDivElement; this.$tasks = select(this.$searchColumn).select('.task-selector').node() as HTMLDivElement; @@ -68,7 +69,7 @@ export default class SearchColumn { this.$searchColumn.remove(); } - private async _setupSearchBar(referenceCht: Cohort) { + private async _setupSearchBar(referenceCht: ICohort) { this.searchBar = new SearchBar(select(this.$searchColumn).select('.search-bar').node() as HTMLDivElement, referenceCht.database, referenceCht.view); this.setSearchBarVisibility(false); // hide searchBar -> set display: none this.searchBar.getSearchBarHTMLDivElement().addEventListener('optionchange', async (e) => { @@ -137,6 +138,7 @@ export default class SearchColumn { private enableAddButtons(enable: boolean): void { if (enable) { // add eventListeners + // eslint-disable-next-line @typescript-eslint/no-this-alias const that = this; select(this.$searchColumn) .selectAll('div.action.add') diff --git a/src/Taskview/Taskview.ts b/src/Taskview/Taskview.ts index 94d6752..4154a51 100644 --- a/src/Taskview/Taskview.ts +++ b/src/Taskview/Taskview.ts @@ -1,9 +1,4 @@ -import { Cohort, EMPTY_COHORT_ID, getEmptyCohort, getLoaderCohort, LOADER_COHORT_ID } from '../Cohort'; -import { ITaskParams, TaskType } from '../CohortInterfaces'; -import { RectCohortRep } from '../CohortRepresentations'; -import { IAttribute, multiAttributeFilter } from '../data/Attribute'; -import { RectangleLayout } from '../Overview/OverviewLayout'; -import { CohortColorSchema, log, removeFromArray, ScrollLinker, SortType } from '../util'; +import { ICohort, IInputCohort, IOutputCohort, ITaskParams, TaskType } from '../app/interfaces'; import { CohortSelectionEvent, COHORT_SELECTION_EVENT_TYPE, @@ -19,669 +14,671 @@ import { PreviewChangeEvent, SplitEvent, SPLIT_EVENT_TYPE, -} from '../utilCustomEvents'; +} from '../base/events'; +import { RectCohortRep } from '../CohortRepresentations'; +import { CoralColorSchema } from '../config/colors'; +import { IAttribute } from '../data/IAttribute'; +import { SortType, removeFromArray, log } from '../util'; +import { ScrollLinker } from '../utils/ScrollLinker'; +import SearchColumn from './SearchColumn'; import AddColumnColumn, { AColumn, ADataColumn, EmptyColumn } from './columns/AColumn'; -import AttributeColumn from './columns/AttributeColumn'; import { InputCohortColumn, OutputCohortColumn } from './columns/CohortColumn'; -import SearchColumn from './SearchColumn'; - -export default class Taskview { - public destroy() { - this.$node.removeEventListener(FILTER_EVENT_TYPE, this.filterListener); - this.$node.removeEventListener(SPLIT_EVENT_TYPE, this.splitListener); - this.$node.removeEventListener(CONFIRM_OUTPUT_EVENT_TYPE, this.confirmListener); - - this.scrollLink.destroy(); - - this.search.destroy(); - this.input.destroy(); - this.output.destroy(); - - this.$node.classList.remove('task-view'); - while (this.$node.hasChildNodes()) { - this.$node.removeChild(this.$node.lastChild); - } - } - - clearOutput() { - this.output.clear(); - this.input.update(); - } - - private input: TaskviewInput; - - private search: SearchColumn; - - private output: TaskviewOutput; - - private scrollLink: ScrollLinker; - - private taskParams: ITaskParams[]; - - private taskAttributes: IAttribute[]; - - private filterListener: EventListenerOrEventListenerObject = (ev) => this.handleFilterEvent(ev as FilterEvent); - - private splitListener: EventListenerOrEventListenerObject = (ev) => this.handleFilterEvent(ev as SplitEvent); +import { EMPTY_COHORT_ID, getEmptyCohort, getLoaderCohort, LOADER_COHORT_ID } from '../Cohort'; +import { multiAttributeFilter } from '../data/Attribute'; +import AttributeColumn from './columns/AttributeColumn'; +import { RectangleLayout } from '../Overview/OverviewLayout'; - private confirmListener: EventListenerOrEventListenerObject = (ev) => this.confirmTask(); // event data (cohorts) currently ignored +abstract class TaskviewTable { + $node: HTMLDivElement; - private columnSortListener: EventListenerOrEventListenerObject = (ev) => this.handleColumnSortEvent(ev as ColumnSortEvent); + $floatingBtns: HTMLDivElement; - constructor(public readonly $node: HTMLDivElement, private reference: Cohort) { - this.$node.classList.add('task-view'); + columns: AColumn[] = []; - const inNode = document.createElement('div'); - this.input = new TaskviewInput(inNode, this.reference, this); - this.$node.appendChild(inNode); + cohorts: ICohort[] = []; - const searchNode = document.createElement('div'); - this.search = new SearchColumn(searchNode, this.reference, this); - this.$node.appendChild(searchNode); + constructor(private $wrapper: HTMLDivElement) { + this.$wrapper.classList.add('task-view-table-button-wrapper'); - const outNode = document.createElement('div'); - this.output = new TaskviewOutput(outNode, this.reference, this); - this.$node.appendChild(outNode); + const tableWrapper = document.createElement('div'); + tableWrapper.classList.add('task-view-scroll-wrapper'); // this div can only be around half the height of the browser (which would lead to column border ending to early for example) --> therefore this is a container holding scrollbars + this.$wrapper.appendChild(tableWrapper); - this.scrollLink = new ScrollLinker(inNode.querySelector('div.task-view-scroll-wrapper'), outNode.querySelector('div.task-view-scroll-wrapper')); + this.$node = document.createElement('div'); // this div will contain the columns of our table that can be higher than half of the viewport + this.$node.classList.add('task-view-table'); + tableWrapper.appendChild(this.$node); + $wrapper.appendChild(tableWrapper); - // Listen to cohort creation events fired by histograms in the input part - this.$node.addEventListener(FILTER_EVENT_TYPE, this.filterListener); - this.$node.addEventListener(SPLIT_EVENT_TYPE, this.splitListener); + $wrapper.insertAdjacentHTML( + 'beforeend', + ` + + `, + ); - // confirmation event that adds the cohrots to cohort graph - this.$node.addEventListener(CONFIRM_OUTPUT_EVENT_TYPE, this.confirmListener); + this.$floatingBtns = $wrapper.querySelector('div.floating-confirm'); + $wrapper.querySelector('div.floating-confirm button.clearBtn').addEventListener('click', () => this.clear()); - // sort event that sorts the input cohorts - this.$node.addEventListener(COLUMN_SORT_EVENT_TYPE, this.columnSortListener); + this.$node.addEventListener(COLUMN_CLOSE_EVENT_TYPE, (ev) => this.removeColumn((ev as ColumnCloseEvent).detail.column)); // arrow function to keep "this" working in eventhandler } - public async handleColumnSortEvent(ev: ColumnSortEvent) { - const sortDetail = ev.detail; - const inputChts = this.getInputCohorts() as InputCohort[]; - if (sortDetail.sortInputChts) { - // sort input cohort - const defaultOrder = this.input.cohortOrder; - await this.sortCohorts(sortDetail.type, inputChts, defaultOrder); - } else { - // sort output cohort for each input cohort - for (const inCht of inputChts) { - const currOutChts = inCht.outputCohorts as OutputCohort[]; - const outputOrder = this.output.cohortOrders.filter((order) => order.inputCht === inCht.dbId); - const defaultOrder = outputOrder.length === 1 ? outputOrder[0].cohorts : currOutChts.map((cht) => cht.dbId); - await this.sortCohorts(sortDetail.type, currOutChts, defaultOrder); - const sizeOutCht = currOutChts.length; - // define the first and last cohort - for (let i = 0; i < sizeOutCht; i++) { - const currCht = currOutChts[i]; - currCht.isFirstOutputCohort = false; - currCht.isLastOutputCohort = false; - // first cohort - if (i === 0) { - currCht.isFirstOutputCohort = true; - } - // last cohort - if (i === sizeOutCht - 1) { - currCht.isLastOutputCohort = true; - } - } - } - } + destroy() { + this.$node.addEventListener(COLUMN_CLOSE_EVENT_TYPE, null); + this.$node.remove(); + } - this.orderCohorts(); + update() { + this.setCohorts(this.cohorts); } - private async sortCohorts(type: SortType, cohortsToSort: Cohort[], defaultOrder: number[]) { - if (type === SortType.Default) { - // sort by default - const sortingArray = defaultOrder; - cohortsToSort.sort((a, b) => this.sortWithDbIdArray(a.dbId, b.dbId, sortingArray)); // default - } else if (type === SortType.Alpha_AZ) { - // sort by label name - cohortsToSort.sort((a, b) => this.sortLabelAlpha(a, b)); // A -> Z - } else if (type === SortType.Alpha_ZA) { - cohortsToSort.sort((a, b) => this.sortLabelAlpha(b, a)); // Z -> A - } else if (type === SortType.Size_19) { - // sort by cohort size - await this.sortCohortsBySize(false, cohortsToSort); - } else if (type === SortType.Size_91) { - // sort by cohort size - await this.sortCohortsBySize(true, cohortsToSort); + public setCohorts(cohorts: ICohort[]) { + this.cohorts = cohorts; + for (const column of this.columns) { + column.setCohorts(cohorts); } - } - private sortWithDbIdArray(a, b, sortingArr) { - return sortingArr.indexOf(a) - sortingArr.indexOf(b); + this.$floatingBtns.hidden = cohorts.filter((cht) => cht.id !== LOADER_COHORT_ID && cht.id !== EMPTY_COHORT_ID).length === 0; } - private sortLabelAlpha(a, b) { - if (a.label < b.label) { - return -1; - } - if (a.label > b.label) { - return 1; - } - return 0; + public addCohort(cht: ICohort) { + this.cohorts.push(cht); + this.setCohorts(this.cohorts); } - private sortSizeNum(a, b) { - if (a.size > b.size) { - return -1; - } - if (a.size < b.size) { - return 1; + public getAttributeColumns(): AttributeColumn[] { + const attCol = []; + for (const ac of this.columns) { + if (ac instanceof AttributeColumn) { + attCol.push(ac); + } } - return 0; + return attCol; } - private async sortCohortsBySize(descending: boolean, cohortsToSort: Cohort[]) { - const chtSizes = []; - for (const cht of cohortsToSort) { - const currSize = await cht.size; - chtSizes.push({ id: cht.id, size: currSize }); + public getUnpinnedAttributeColumns(): AttributeColumn[] { + const attCol = []; + for (const ac of this.columns) { + if (ac instanceof AttributeColumn) { + if (!ac.pinned) { + attCol.push(ac); + } + } } + return attCol; + } - if (descending) { - chtSizes.sort((a, b) => this.sortSizeNum(a, b)); // 9 -> 1 - } else { - chtSizes.sort((a, b) => this.sortSizeNum(b, a)); // 1 -> 9 + public addAttributeColumn(attr: IAttribute, allowDuplicates = false, onInputCohortSide = true, color = false, pinned = false) { + if ( + allowDuplicates || + !this.columns.find((column) => column instanceof AttributeColumn && (column as AttributeColumn).attribute.dataKey === attr.dataKey) + ) { + // if duplicates are allowed or the column wasn't added yet + const newCol = new AttributeColumn(attr, this.$node, onInputCohortSide, color, pinned); + newCol.setCohorts(this.cohorts); + this.columns.unshift(newCol); // add columnt as first element + // only adding the new column as first element doesn't reorder column HTML elements + // because the new one gets added at the end -> set order attribute to define order of columns + let orderCnt = 0; + this.columns.forEach((elem) => { + if (elem instanceof AttributeColumn) { + elem.setOrder(orderCnt); + orderCnt++; + } + }); + window.dispatchEvent(new Event('resize')); // update vega chart sizes in case the columns became narrower } - - cohortsToSort.sort(function (a, b) { - const aId = a.id; - const bId = b.id; - const chtSizesIds = chtSizes.map((elem) => elem.id); - if (chtSizesIds.indexOf(aId) > chtSizesIds.indexOf(bId)) { - return 1; - } - if (chtSizesIds.indexOf(aId) < chtSizesIds.indexOf(bId)) { - return -1; - } - return 0; - }); } - public orderCohorts() { - // order input side - const inputColumns: ADataColumn[] = this.input.columns as any; - inputColumns.forEach((element) => element.orderCohorts(this.getInputCohorts())); - // order input side - const outputColumns: ADataColumn[] = this.output.columns as any; - const outChts = [].concat(...this.input.cohorts.map((cht) => cht.outputCohorts)); - outputColumns.forEach((element) => element.orderCohorts(outChts)); + public removeColumn(col: AColumn) { + removeFromArray(this.columns, col); + window.dispatchEvent(new Event('resize')); // update vega chart sizes in case the columns became wider } - public confirmTask() { - this.search.clear(); - this.removeAttributeColumns(); - this.$node.dispatchEvent(new ConfirmTaskEvent(this.taskParams, this.taskAttributes)); + clear() { + // this.columns.filter((col) => !(col instanceof OutputCohortColumn || col instanceof EmptyColumn)).forEach((col) => col.close()); //close all but default columns + this.setCohorts([]); } +} - public setInputCohorts(cohorts: Cohort[]): void { - this.input.setCohorts(cohorts as InputCohort[]); - this.search.updateTasks(); - const outChts = [].concat(...this.input.cohorts.map((cht) => cht.outputCohorts)); - this.setOutputCohorts(outChts); - } +class TaskviewInput extends TaskviewTable { + cohortOrder: number[]; - public updateInput() { - this.input.update(); // adjust height after removing output cohorts - } + cohorts: IInputCohort[] = []; - public getInputCohorts(): Cohort[] { - return this.input.cohorts; - } + usedColorsForCohorts = CoralColorSchema.COLOR_SCHEME.map((elem) => { + return { color: elem, cohorts: [] }; + }); - public getOutputCohorts(): Cohort[] { - return this.output ? this.output.cohorts : []; - } + private inputCohortCol: InputCohortColumn; - public setOutputCohorts(cohorts: Cohort[]): void { - this.output.setCohorts(cohorts); - } + maxColors: number; - public setReference(reference: Cohort): void { - this.reference = reference; - } + constructor($wrapper: HTMLDivElement, reference: ICohort, private taskview: Taskview) { + super($wrapper); + this.$node.classList.add('input'); - public addMultipleAttributeColumns(dArray: IAttribute[], allowDuplicates = false, pinned = false) { - dArray.forEach((d) => this.addAttributeColumn(d, allowDuplicates, pinned)); + // this.columns.push(new NumberColumn(this.$node)); + this.inputCohortCol = new InputCohortColumn(this.$node); + this.columns.push(new AddColumnColumn(this.$node, taskview, reference.database, reference.view)); + this.columns.push(this.inputCohortCol); + // this.columns.push(new PrevalenceColumn(reference, this.$node)); + this.columns.push(new EmptyColumn(this.$node)); + this.clearColorCohorts(); } - public addAttributeColumn(d: IAttribute, allowDuplicates = false, pinned = false) { - if (this.reference.idColumn.column !== d.id) { - this.addAttributeColumnForInput(d, allowDuplicates, pinned); - this.addAttributeColumnForOutput(d, allowDuplicates, pinned); - } + private clearColorCohorts() { + // setup color options + this.usedColorsForCohorts = CoralColorSchema.COLOR_SCHEME.map((elem) => { + return { color: elem, cohorts: [] }; + }); + this.maxColors = this.usedColorsForCohorts.length; } - public addAttributeColumnForInput(d: IAttribute, allowDuplicates = false, pinned = false) { - this.input.addAttributeColumn(d, allowDuplicates, pinned); // function is overwritten in and does not need the onInputCohortSide = true variable - } + public setCohorts(cohorts: IInputCohort[]) { + this.clearColorCohorts(); + cohorts.filter((cht) => !cht.outputCohorts).forEach((cht) => (cht.outputCohorts = [])); // handle undefined outputCohort array - public addAttributeColumnForOutput(d: IAttribute, allowDuplicates = false, pinned = false) { - this.output.addAttributeColumn(d, allowDuplicates, false, false, pinned); - } + // set selction order of cohorts + this.cohortOrder = cohorts.map((cht) => cht.dbId); + this.inputCohortCol.setDefaultSort(); - public removeAttributeColumns() { - this.input.getUnpinnedAttributeColumns().forEach((col) => col.close()); - this.output.getUnpinnedAttributeColumns().forEach((col) => col.close()); - } + // get all cohorts that have already a color + cohorts + .filter((cht) => cht.colorTaskView) + .forEach((cht) => { + const colorIndex = this.usedColorsForCohorts.map((a) => a.color).indexOf(cht.colorTaskView); + if (colorIndex !== -1) { + this.usedColorsForCohorts[colorIndex].cohorts.push(cht.id); + } + }); - public getTaskParams(): ITaskParams[] { - return this.taskParams; - } + // assign color to cohort without one + const maxCohortPerColor = Math.ceil(cohorts.length / this.maxColors); + cohorts.forEach((elem, i) => { + const colorIndex = i % this.maxColors; // circle through all colors - public getTaskAttributes(): IAttribute[] { - return this.taskAttributes; + // check if color exists + if (elem.colorTaskView === null) { + // check if the color for the current cohort index is available + if (this.usedColorsForCohorts[colorIndex].cohorts.length < maxCohortPerColor) { + this.usedColorsForCohorts[colorIndex].cohorts.push(elem.id); // add cohort to the cohort array for the color + elem.colorTaskView = this.usedColorsForCohorts[colorIndex].color; // set color for the cohort + } else { + // go through all possible color and use the first one not used + for (const cc of this.usedColorsForCohorts) { + if (cc.cohorts.length < maxCohortPerColor) { + cc.cohorts.push(elem.id); // add cohort to the cohort array for the color + elem.colorTaskView = cc.color; // set color for the cohort + break; + } + } + } + } + }); + super.setCohorts(cohorts); } - private currentEvent = 0; + public addAttributeColumn(attr: IAttribute, allowDuplicates = false, pinned = false) { + super.addAttributeColumn(attr, allowDuplicates, true, true, pinned); + } - async handleFilterEvent(ev: FilterEvent | SplitEvent) { - const currentEv = ++this.currentEvent; - let outputCohorts = []; // Stores the output cohorts in correct order, will replace the array currently used - const taskWithSelectedOutput: ITaskParams[] = []; - this.taskParams = []; - this.taskAttributes = ev.detail.desc[0].filter.map((filter) => filter.attr); + clear() { + this.cohorts + .slice() // duplicate because the cohort array will change through the event + .forEach((cht) => this.$node.dispatchEvent(new CohortSelectionEvent(cht))); // deselect each + super.clear(); + } +} - for (const inCht of this.input.cohorts) { - const chtBins = ev.detail.desc.filter((bin) => inCht.id === bin.cohort.id); - const outChts = new Array(Math.max(chtBins.length, 1)).fill(null).map(() => getLoaderCohort(inCht)); +class TaskviewOutput extends TaskviewTable { + cohortOrders: { inputCht: number; cohorts: number[] }[]; - (outChts[outChts.length - 1] as OutputCohort).isLastOutputCohort = true; - (outChts[0] as OutputCohort).isFirstOutputCohort = true; + private outputCohortCol: OutputCohortColumn; - inCht.outputCohorts = outChts; - outputCohorts.push(...outChts); - } + constructor($wrapper: HTMLDivElement, reference: ICohort, private taskview: Taskview) { + super($wrapper); + $wrapper.classList.add('output'); - // Update the input cohorts - this.updateInput(); - // Add the new cohorts to the output side - this.setOutputCohorts(outputCohorts); + this.$floatingBtns.insertAdjacentHTML( + `beforeend`, + ` + + `, + ); + $wrapper + .querySelector('div.floating-confirm button.confirmBtn') + .addEventListener('click', (clickEv) => clickEv.target.dispatchEvent(new ConfirmOutputEvent(this.cohorts))); - // await DebugTools.sleep(1500); - outputCohorts = []; + this.columns.push(new EmptyColumn(this.$node)); // same flex order as outputcohort column -> ordered by position in DOM + this.columns.push(new AddColumnColumn(this.$node, taskview, reference.database, reference.view, false)); + this.outputCohortCol = new OutputCohortColumn(this.$node); + this.columns.push(this.outputCohortCol); - // For each input cohort, create a new output cohort - for (const cht of this.input.cohorts) { - log.debug('filter/split event: ', ev); - cht.outputCohorts = []; - const chtBins = ev.detail.desc.filter((bin) => cht.id === bin.cohort.id); - if (chtBins.length > 0) { - const chtPromises = []; - for (const bin of chtBins) { - chtPromises.push(multiAttributeFilter(cht, bin.filter)); + this.$node.addEventListener(COHORT_SELECTION_EVENT_TYPE, (ev: CohortSelectionEvent) => { + ev.stopPropagation(); // prevent this ev from going to the global selection handler that sets the taskview inputs + ev.detail.cohort.selected = !ev.detail.cohort.selected; + const updatedTaskParams: ITaskParams[] = []; + // only add the output cohorts that are selected to each of the task parameters + for (const tsk of this.taskview.getTaskParams()) { + const selectedOutputCohorts = tsk.outputCohorts.filter((a) => a.selected === true); + // check if task has output cohorts + if (selectedOutputCohorts.length > 0) { + updatedTaskParams.push({ + inputCohorts: tsk.inputCohorts, + outputCohorts: selectedOutputCohorts, + type: tsk.type, + label: tsk.label, + }); } + } + // update the preview to only show the selected output cohorts + this.$node.dispatchEvent(new PreviewChangeEvent(updatedTaskParams, this.taskview.getTaskAttributes())); + this.update(); + }); + } - const newChts = await Promise.all(chtPromises); - if (currentEv !== this.currentEvent) { - return; - } + clear() { + super.clear(); - const chtSizes = []; - newChts.sort((a, b) => this.sortLabelAlpha(a, b)); // sort output cohorts: A -> Z - for (const newOutCht of newChts) { - // Set representation of new cohort - const layout = new RectangleLayout(); - newOutCht.representation = new RectCohortRep(newOutCht, layout.rowHeight, layout.cohortWidth); - const sizePromises = [newOutCht.size, this.reference.size]; - chtSizes.push(...sizePromises); - Promise.all(sizePromises).then(([newSize, refSize]) => { - newOutCht.representation.setSize(newSize, refSize); - if (newSize > 0) { - newOutCht.selected = true; - } - }); + this.taskview.getInputCohorts().forEach((cht) => ((cht as IInputCohort).outputCohorts = [])); + this.taskview.updateInput(); + // remove the preview by setting the taskParams to an empty array + this.$node.dispatchEvent(new PreviewChangeEvent([], null)); + } - (newOutCht as Cohort).setCohortParents([cht]); - cht.outputCohorts.push(newOutCht); // Add new output cohort to existing cohorts - } + public setCohorts(cohorts: ICohort[]) { + super.setCohorts(cohorts); - await Promise.all(chtSizes); // wait for the cohort sizes to properly display the representation + // set order of output cohorts for each input cohort + this.cohortOrders = []; + for (const cht of cohorts) { + const existingParents = this.cohortOrders.map((o) => o.inputCht); + const parentdbID = cht.getCohortParents()[0].dbId; + const index = existingParents.indexOf(parentdbID); + if (index === -1) { + this.cohortOrders.push({ + inputCht: parentdbID, + cohorts: [cht.dbId], + }); } else { - cht.outputCohorts.push(getEmptyCohort(cht)); + this.cohortOrders[index].cohorts.push(cht.dbId); } + } + this.outputCohortCol.setDefaultSort(); + } +} - // the async/time instensive stuff is done now, check if we should continue: - if (currentEv !== this.currentEvent) { - return; - } +export default class Taskview { + public destroy() { + this.$node.removeEventListener(FILTER_EVENT_TYPE, this.filterListener); + this.$node.removeEventListener(SPLIT_EVENT_TYPE, this.splitListener); + this.$node.removeEventListener(CONFIRM_OUTPUT_EVENT_TYPE, this.confirmListener); - (cht.outputCohorts[cht.outputCohorts.length - 1] as OutputCohort).isLastOutputCohort = true; - (cht.outputCohorts[0] as OutputCohort).isFirstOutputCohort = true; - outputCohorts.push(...cht.outputCohorts); // add all output cohorts of current input cohorts (ensures correct order in output side) + this.scrollLink.destroy(); - if (chtBins.length > 0) { - // create current task params - const currTaskParam: ITaskParams = { - inputCohorts: [cht], - outputCohorts: cht.outputCohorts, - type: ev instanceof FilterEvent ? TaskType.Filter : TaskType.Split, - label: ev.detail.desc[0].filter.map((filter) => filter.attr.label).join(', '), - }; - // save all curertn possibel task params - this.taskParams.push(currTaskParam); - // check if a task generates selected output cohorts - if (cht.outputCohorts.filter((elem) => elem.selected === true).length >= 1) { - // initially onyl selected output cohorts will be shown in overview - taskWithSelectedOutput.push(currTaskParam); - } - } + this.search.destroy(); + this.input.destroy(); + this.output.destroy(); + + this.$node.classList.remove('task-view'); + while (this.$node.hasChildNodes()) { + this.$node.removeChild(this.$node.lastChild); } + } - // Update the input cohorts - this.updateInput(); + clearOutput() { + this.output.clear(); + this.input.update(); + } - // show the preview for the current task - this.$node.dispatchEvent(new PreviewChangeEvent(taskWithSelectedOutput, this.taskAttributes)); + private input: TaskviewInput; - // Add the new cohorts to the output side - this.setOutputCohorts(outputCohorts); - ev.detail.desc[0].filter.forEach((filter) => this.addAttributeColumn(filter.attr)); - } + private search: SearchColumn; - showOutput(show: boolean) { - const hide = !show; - // this.output.$node.style.display = hide ? 'none' : 'flex'; // setting hidden does not work with flexbox + private output: TaskviewOutput; - this.$node.classList.toggle('no-output', hide); - } -} + private scrollLink: ScrollLinker; -abstract class TaskviewTable { - $node: HTMLDivElement; + private taskParams: ITaskParams[]; - $floatingBtns: HTMLDivElement; + private taskAttributes: IAttribute[]; - columns: AColumn[] = []; + private filterListener: EventListenerOrEventListenerObject = (ev) => this.handleFilterEvent(ev as FilterEvent); - cohorts: Cohort[] = []; + private splitListener: EventListenerOrEventListenerObject = (ev) => this.handleFilterEvent(ev as SplitEvent); - constructor(private $wrapper: HTMLDivElement) { - this.$wrapper.classList.add('task-view-table-button-wrapper'); + private confirmListener: EventListenerOrEventListenerObject = (ev) => this.confirmTask(); // event data (cohorts) currently ignored - const tableWrapper = document.createElement('div'); - tableWrapper.classList.add('task-view-scroll-wrapper'); // this div can only be around half the height of the browser (which would lead to column border ending to early for example) --> therefore this is a container holding scrollbars - this.$wrapper.appendChild(tableWrapper); + private columnSortListener: EventListenerOrEventListenerObject = (ev) => this.handleColumnSortEvent(ev as ColumnSortEvent); - this.$node = document.createElement('div'); // this div will contain the columns of our table that can be higher than half of the viewport - this.$node.classList.add('task-view-table'); - tableWrapper.appendChild(this.$node); - $wrapper.appendChild(tableWrapper); + constructor(public readonly $node: HTMLDivElement, private reference: ICohort) { + this.$node.classList.add('task-view'); - $wrapper.insertAdjacentHTML( - 'beforeend', - ` - - `, - ); + const inNode = document.createElement('div'); + this.input = new TaskviewInput(inNode, this.reference, this); + this.$node.appendChild(inNode); - this.$floatingBtns = $wrapper.querySelector('div.floating-confirm'); - $wrapper.querySelector('div.floating-confirm button.clearBtn').addEventListener('click', () => this.clear()); + const searchNode = document.createElement('div'); + this.search = new SearchColumn(searchNode, this.reference, this); + this.$node.appendChild(searchNode); - this.$node.addEventListener(COLUMN_CLOSE_EVENT_TYPE, (ev) => this.removeColumn((ev as ColumnCloseEvent).detail.column)); // arrow function to keep "this" working in eventhandler - } + const outNode = document.createElement('div'); + this.output = new TaskviewOutput(outNode, this.reference, this); + this.$node.appendChild(outNode); - destroy() { - this.$node.addEventListener(COLUMN_CLOSE_EVENT_TYPE, null); - this.$node.remove(); - } + this.scrollLink = new ScrollLinker(inNode.querySelector('div.task-view-scroll-wrapper'), outNode.querySelector('div.task-view-scroll-wrapper')); - update() { - this.setCohorts(this.cohorts); + // Listen to cohort creation events fired by histograms in the input part + this.$node.addEventListener(FILTER_EVENT_TYPE, this.filterListener); + this.$node.addEventListener(SPLIT_EVENT_TYPE, this.splitListener); + + // confirmation event that adds the cohrots to cohort graph + this.$node.addEventListener(CONFIRM_OUTPUT_EVENT_TYPE, this.confirmListener); + + // sort event that sorts the input cohorts + this.$node.addEventListener(COLUMN_SORT_EVENT_TYPE, this.columnSortListener); } - public setCohorts(cohorts: Cohort[]) { - this.cohorts = cohorts; - for (const column of this.columns) { - column.setCohorts(cohorts); + public async handleColumnSortEvent(ev: ColumnSortEvent) { + const sortDetail = ev.detail; + const inputChts = this.getInputCohorts() as IInputCohort[]; + if (sortDetail.sortInputChts) { + // sort input cohort + const defaultOrder = this.input.cohortOrder; + await this.sortCohorts(sortDetail.type, inputChts, defaultOrder); + } else { + // sort output cohort for each input cohort + for (const inCht of inputChts) { + const currOutChts = inCht.outputCohorts as IOutputCohort[]; + const outputOrder = this.output.cohortOrders.filter((order) => order.inputCht === inCht.dbId); + const defaultOrder = outputOrder.length === 1 ? outputOrder[0].cohorts : currOutChts.map((cht) => cht.dbId); + // TODO: fix me + // eslint-disable-next-line no-await-in-loop + await this.sortCohorts(sortDetail.type, currOutChts, defaultOrder); + const sizeOutCht = currOutChts.length; + // define the first and last cohort + for (let i = 0; i < sizeOutCht; i++) { + const currCht = currOutChts[i]; + currCht.isFirstOutputCohort = false; + currCht.isLastOutputCohort = false; + // first cohort + if (i === 0) { + currCht.isFirstOutputCohort = true; + } + // last cohort + if (i === sizeOutCht - 1) { + currCht.isLastOutputCohort = true; + } + } + } } - this.$floatingBtns.hidden = cohorts.filter((cht) => cht.id !== LOADER_COHORT_ID && cht.id !== EMPTY_COHORT_ID).length === 0; + this.orderCohorts(); } - public addCohort(cht: Cohort) { - this.cohorts.push(cht); - this.setCohorts(this.cohorts); + private async sortCohorts(type: SortType, cohortsToSort: ICohort[], defaultOrder: number[]) { + if (type === SortType.Default) { + // sort by default + const sortingArray = defaultOrder; + cohortsToSort.sort((a, b) => this.sortWithDbIdArray(a.dbId, b.dbId, sortingArray)); // default + } else if (type === SortType.Alpha_AZ) { + // sort by label name + cohortsToSort.sort((a, b) => this.sortLabelAlpha(a, b)); // A -> Z + } else if (type === SortType.Alpha_ZA) { + cohortsToSort.sort((a, b) => this.sortLabelAlpha(b, a)); // Z -> A + } else if (type === SortType.Size_19) { + // sort by cohort size + await this.sortCohortsBySize(false, cohortsToSort); + } else if (type === SortType.Size_91) { + // sort by cohort size + await this.sortCohortsBySize(true, cohortsToSort); + } } - public getAttributeColumns(): AttributeColumn[] { - const attCol = []; - for (const ac of this.columns) { - if (ac instanceof AttributeColumn) { - attCol.push(ac); - } + private sortWithDbIdArray(a, b, sortingArr) { + return sortingArr.indexOf(a) - sortingArr.indexOf(b); + } + + private sortLabelAlpha(a, b) { + if (a.label < b.label) { + return -1; } - return attCol; + if (a.label > b.label) { + return 1; + } + return 0; } - public getUnpinnedAttributeColumns(): AttributeColumn[] { - const attCol = []; - for (const ac of this.columns) { - if (ac instanceof AttributeColumn) { - if (!ac.pinned) { - attCol.push(ac); - } - } + private sortSizeNum(a, b) { + if (a.size > b.size) { + return -1; } - return attCol; + if (a.size < b.size) { + return 1; + } + return 0; } - public addAttributeColumn(attr: IAttribute, allowDuplicates = false, onInputCohortSide = true, color = false, pinned = false) { - if ( - allowDuplicates || - !this.columns.find((column) => column instanceof AttributeColumn && (column as AttributeColumn).attribute.dataKey === attr.dataKey) - ) { - // if duplicates are allowed or the column wasn't added yet - const newCol = new AttributeColumn(attr, this.$node, onInputCohortSide, color, pinned); - newCol.setCohorts(this.cohorts); - this.columns.unshift(newCol); // add columnt as first element - // only adding the new column as first element doesn't reorder column HTML elements - // because the new one gets added at the end -> set order attribute to define order of columns - let orderCnt = 0; - this.columns.map((elem) => { - if (elem instanceof AttributeColumn) { - elem.setOrder(orderCnt); - orderCnt++; - } - }); - window.dispatchEvent(new Event('resize')); // update vega chart sizes in case the columns became narrower + private async sortCohortsBySize(descending: boolean, cohortsToSort: ICohort[]) { + const chtSizes = await Promise.all( + cohortsToSort.map(async (cht) => { + const currSize = await cht.size; + return { id: cht.id, size: currSize }; + }), + ); + if (descending) { + chtSizes.sort((a, b) => this.sortSizeNum(a, b)); // 9 -> 1 + } else { + chtSizes.sort((a, b) => this.sortSizeNum(b, a)); // 1 -> 9 } + + cohortsToSort.sort(function (a, b) { + const aId = a.id; + const bId = b.id; + const chtSizesIds = chtSizes.map((elem) => elem.id); + if (chtSizesIds.indexOf(aId) > chtSizesIds.indexOf(bId)) { + return 1; + } + if (chtSizesIds.indexOf(aId) < chtSizesIds.indexOf(bId)) { + return -1; + } + return 0; + }); } - public removeColumn(col: AColumn) { - removeFromArray(this.columns, col); - window.dispatchEvent(new Event('resize')); // update vega chart sizes in case the columns became wider + public orderCohorts() { + // order input side + const inputColumns: ADataColumn[] = this.input.columns as any; + inputColumns.forEach((element) => element.orderCohorts(this.getInputCohorts())); + // order input side + const outputColumns: ADataColumn[] = this.output.columns as any; + const outChts = [].concat(...this.input.cohorts.map((cht) => cht.outputCohorts)); + outputColumns.forEach((element) => element.orderCohorts(outChts)); + } + + public confirmTask() { + this.search.clear(); + this.removeAttributeColumns(); + this.$node.dispatchEvent(new ConfirmTaskEvent(this.taskParams, this.taskAttributes)); } - clear() { - // this.columns.filter((col) => !(col instanceof OutputCohortColumn || col instanceof EmptyColumn)).forEach((col) => col.close()); //close all but default columns - this.setCohorts([]); + public setInputCohorts(cohorts: ICohort[]): void { + this.input.setCohorts(cohorts as IInputCohort[]); + this.search.updateTasks(); + const outChts = [].concat(...this.input.cohorts.map((cht) => cht.outputCohorts)); + this.setOutputCohorts(outChts); } -} - -class TaskviewInput extends TaskviewTable { - cohortOrder: number[]; - - cohorts: InputCohort[]; - - usedColorsForCohorts = CohortColorSchema.COLOR_SCHEME.map((elem) => { - return { color: elem, cohorts: [] }; - }); - private inputCohortCol: InputCohortColumn; + public updateInput() { + this.input.update(); // adjust height after removing output cohorts + } - maxColors: number; + public getInputCohorts(): IInputCohort[] { + return this.input.cohorts; + } - constructor($wrapper: HTMLDivElement, reference: Cohort, private taskview: Taskview) { - super($wrapper); - this.$node.classList.add('input'); + public getOutputCohorts(): ICohort[] { + return this.output ? this.output.cohorts : []; + } - // this.columns.push(new NumberColumn(this.$node)); - this.inputCohortCol = new InputCohortColumn(this.$node); - this.columns.push(new AddColumnColumn(this.$node, taskview, reference.database, reference.view)); - this.columns.push(this.inputCohortCol); - // this.columns.push(new PrevalenceColumn(reference, this.$node)); - this.columns.push(new EmptyColumn(this.$node)); - this.clearColorCohorts(); + public setOutputCohorts(cohorts: ICohort[]): void { + this.output.setCohorts(cohorts); } - private clearColorCohorts() { - // setup color options - this.usedColorsForCohorts = CohortColorSchema.COLOR_SCHEME.map((elem) => { - return { color: elem, cohorts: [] }; - }); - this.maxColors = this.usedColorsForCohorts.length; + public setReference(reference: ICohort): void { + this.reference = reference; } - public setCohorts(cohorts: InputCohort[]) { - this.clearColorCohorts(); - cohorts.filter((cht) => !cht.outputCohorts).forEach((cht) => (cht.outputCohorts = [])); // handle undefined outputCohort array + public addMultipleAttributeColumns(dArray: IAttribute[], allowDuplicates = false, pinned = false) { + dArray.forEach((d) => this.addAttributeColumn(d, allowDuplicates, pinned)); + } - // set selction order of cohorts - this.cohortOrder = cohorts.map((cht) => cht.dbId); - this.inputCohortCol.setDefaultSort(); + public addAttributeColumn(d: IAttribute, allowDuplicates = false, pinned = false) { + if (this.reference.idColumn.column !== d.id) { + this.addAttributeColumnForInput(d, allowDuplicates, pinned); + this.addAttributeColumnForOutput(d, allowDuplicates, pinned); + } + } - // get all cohorts that have already a color - cohorts - .filter((cht) => cht.colorTaskView) - .forEach((cht) => { - const colorIndex = this.usedColorsForCohorts.map((a) => a.color).indexOf(cht.colorTaskView); - if (colorIndex !== -1) { - this.usedColorsForCohorts[colorIndex].cohorts.push(cht.id); - } - }); + public addAttributeColumnForInput(d: IAttribute, allowDuplicates = false, pinned = false) { + this.input.addAttributeColumn(d, allowDuplicates, pinned); // function is overwritten in and does not need the onInputCohortSide = true variable + } - // assign color to cohort without one - const maxCohortPerColor = Math.ceil(cohorts.length / this.maxColors); - cohorts.forEach((elem, i) => { - const colorIndex = i % this.maxColors; // circle through all colors + public addAttributeColumnForOutput(d: IAttribute, allowDuplicates = false, pinned = false) { + this.output.addAttributeColumn(d, allowDuplicates, false, false, pinned); + } - // check if color exists - if (elem.colorTaskView === null) { - // check if the color for the current cohort index is available - if (this.usedColorsForCohorts[colorIndex].cohorts.length < maxCohortPerColor) { - this.usedColorsForCohorts[colorIndex].cohorts.push(elem.id); // add cohort to the cohort array for the color - elem.colorTaskView = this.usedColorsForCohorts[colorIndex].color; // set color for the cohort - } else { - // go through all possible color and use the first one not used - for (const cc of this.usedColorsForCohorts) { - if (cc.cohorts.length < maxCohortPerColor) { - cc.cohorts.push(elem.id); // add cohort to the cohort array for the color - elem.colorTaskView = cc.color; // set color for the cohort - break; - } - } - } - } - }); - super.setCohorts(cohorts); + public removeAttributeColumns() { + this.input.getUnpinnedAttributeColumns().forEach((col) => col.close()); + this.output.getUnpinnedAttributeColumns().forEach((col) => col.close()); } - public addAttributeColumn(attr: IAttribute, allowDuplicates = false, pinned = false) { - super.addAttributeColumn(attr, allowDuplicates, true, true, pinned); + public getTaskParams(): ITaskParams[] { + return this.taskParams; } - clear() { - this.cohorts - .slice() // duplicate because the cohort array will change through the event - .forEach((cht) => this.$node.dispatchEvent(new CohortSelectionEvent(cht))); // deselect each - super.clear(); + public getTaskAttributes(): IAttribute[] { + return this.taskAttributes; } -} -class TaskviewOutput extends TaskviewTable { - cohortOrders: { inputCht: number; cohorts: number[] }[]; + private currentEvent = 0; - private outputCohortCol: OutputCohortColumn; + async handleFilterEvent(ev: FilterEvent | SplitEvent) { + const currentEv = ++this.currentEvent; + let outputCohorts: IOutputCohort[] = []; // Stores the output cohorts in correct order, will replace the array currently used + const taskWithSelectedOutput: ITaskParams[] = []; + this.taskParams = []; + this.taskAttributes = ev.detail.desc[0].filter.map((filter) => filter.attr); - constructor($wrapper: HTMLDivElement, reference: Cohort, private taskview: Taskview) { - super($wrapper); - $wrapper.classList.add('output'); + for (const inCht of this.input.cohorts) { + const chtBins = ev.detail.desc.filter((bin) => inCht.id === bin.cohort.id); + const outChts: IOutputCohort[] = new Array(Math.max(chtBins.length, 1)).fill(null).map(() => getLoaderCohort(inCht) as unknown as IOutputCohort); - this.$floatingBtns.insertAdjacentHTML( - `beforeend`, - ` - - `, - ); - $wrapper - .querySelector('div.floating-confirm button.confirmBtn') - .addEventListener('click', (clickEv) => clickEv.target.dispatchEvent(new ConfirmOutputEvent(this.cohorts))); + outChts[outChts.length - 1].isLastOutputCohort = true; + outChts[0].isFirstOutputCohort = true; - this.columns.push(new EmptyColumn(this.$node)); // same flex order as outputcohort column -> ordered by position in DOM - this.columns.push(new AddColumnColumn(this.$node, taskview, reference.database, reference.view, false)); - this.outputCohortCol = new OutputCohortColumn(this.$node); - this.columns.push(this.outputCohortCol); + inCht.outputCohorts = outChts; + outputCohorts.push(...outChts); + } - this.$node.addEventListener(COHORT_SELECTION_EVENT_TYPE, (ev: CohortSelectionEvent) => { - ev.stopPropagation(); // prevent this ev from going to the global selection handler that sets the taskview inputs - ev.detail.cohort.selected = !ev.detail.cohort.selected; - const updatedTaskParams: ITaskParams[] = []; - // only add the output cohorts that are selected to each of the task parameters - for (const tsk of this.taskview.getTaskParams()) { - const selectedOutputCohorts = tsk.outputCohorts.filter((a) => a.selected === true); - // check if task has output cohorts - if (selectedOutputCohorts.length > 0) { - updatedTaskParams.push({ - inputCohorts: tsk.inputCohorts, - outputCohorts: selectedOutputCohorts, - type: tsk.type, - label: tsk.label, + // Update the input cohorts + this.updateInput(); + // Add the new cohorts to the output side + this.setOutputCohorts(outputCohorts); + + // await DebugTools.sleep(1500); + outputCohorts = []; + + // For each input cohort, create a new output cohort + for (const cht of this.input.cohorts) { + log.debug('filter/split event: ', ev); + cht.outputCohorts = []; + const chtBins = ev.detail.desc.filter((bin) => cht.id === bin.cohort.id); + if (chtBins.length > 0) { + const chtPromises = []; + for (const bin of chtBins) { + chtPromises.push(multiAttributeFilter(cht, bin.filter)); + } + // TODO: fix me + // eslint-disable-next-line no-await-in-loop + const newChts = await Promise.all(chtPromises); + if (currentEv !== this.currentEvent) { + return; + } + + const chtSizes = []; + newChts.sort((a, b) => this.sortLabelAlpha(a, b)); // sort output cohorts: A -> Z + for (const newOutCht of newChts) { + // Set representation of new cohort + const layout = new RectangleLayout(); + newOutCht.representation = new RectCohortRep(newOutCht, layout.rowHeight, layout.cohortWidth); + const sizePromises = [newOutCht.size, this.reference.size]; + chtSizes.push(...sizePromises); + Promise.all(sizePromises).then(([newSize, refSize]) => { + newOutCht.representation.setSize(newSize, refSize); + if (newSize > 0) { + newOutCht.selected = true; + } }); + + newOutCht.setCohortParents([cht]); + cht.outputCohorts.push(newOutCht); // Add new output cohort to existing cohorts } + // TODO: fix me + // eslint-disable-next-line no-await-in-loop + await Promise.all(chtSizes); // wait for the cohort sizes to properly display the representation + } else { + cht.outputCohorts.push(getEmptyCohort(cht) as IOutputCohort); } - // update the preview to only show the selected output cohorts - this.$node.dispatchEvent(new PreviewChangeEvent(updatedTaskParams, this.taskview.getTaskAttributes())); - this.update(); - }); - } - clear() { - super.clear(); - - this.taskview.getInputCohorts().forEach((cht) => ((cht as InputCohort).outputCohorts = [])); - this.taskview.updateInput(); - // remove the preview by setting the taskParams to an empty array - this.$node.dispatchEvent(new PreviewChangeEvent([], null)); - } + // the async/time instensive stuff is done now, check if we should continue: + if (currentEv !== this.currentEvent) { + return; + } - public setCohorts(cohorts: Cohort[]) { - super.setCohorts(cohorts); + cht.outputCohorts[cht.outputCohorts.length - 1].isLastOutputCohort = true; + cht.outputCohorts[0].isFirstOutputCohort = true; + outputCohorts.push(...cht.outputCohorts); // add all output cohorts of current input cohorts (ensures correct order in output side) - // set order of output cohorts for each input cohort - this.cohortOrders = []; - for (const cht of cohorts) { - const existingParents = this.cohortOrders.map((o) => o.inputCht); - const parentdbID = cht.getCohortParents()[0].dbId; - const index = existingParents.indexOf(parentdbID); - if (index === -1) { - this.cohortOrders.push({ - inputCht: parentdbID, - cohorts: [cht.dbId], - }); - } else { - this.cohortOrders[index].cohorts.push(cht.dbId); + if (chtBins.length > 0) { + // create current task params + const currTaskParam: ITaskParams = { + inputCohorts: [cht], + outputCohorts: cht.outputCohorts, + type: ev instanceof FilterEvent ? TaskType.Filter : TaskType.Split, + label: ev.detail.desc[0].filter.map((filter) => filter.attr.label).join(', '), + }; + // save all curertn possibel task params + this.taskParams.push(currTaskParam); + // check if a task generates selected output cohorts + if (cht.outputCohorts.filter((elem) => elem.selected === true).length >= 1) { + // initially onyl selected output cohorts will be shown in overview + taskWithSelectedOutput.push(currTaskParam); + } } } - this.outputCohortCol.setDefaultSort(); - } -} -export class InputCohort extends Cohort { - outputCohorts: Cohort[] = []; -} + // Update the input cohorts + this.updateInput(); + + // show the preview for the current task + this.$node.dispatchEvent(new PreviewChangeEvent(taskWithSelectedOutput, this.taskAttributes)); + + // Add the new cohorts to the output side + this.setOutputCohorts(outputCohorts); + ev.detail.desc[0].filter.forEach((filter) => this.addAttributeColumn(filter.attr)); + } -export class OutputCohort extends Cohort { - public isLastOutputCohort = false; // used to add a paddding between outputcohorts of different input cohorts + showOutput(show: boolean) { + const hide = !show; + // this.output.$node.style.display = hide ? 'none' : 'flex'; // setting hidden does not work with flexbox - public isFirstOutputCohort = false; // used to add a paddding between outputcohorts of different input cohorts + this.$node.classList.toggle('no-output', hide); + } } diff --git a/src/Taskview/columns/AColumn.ts b/src/Taskview/columns/AColumn.ts index da3e2cd..88f410f 100644 --- a/src/Taskview/columns/AColumn.ts +++ b/src/Taskview/columns/AColumn.ts @@ -1,11 +1,74 @@ -import {select} from 'd3v7'; -import {Cohort, EMPTY_COHORT_ID, LOADER_COHORT_ID} from '../../Cohort'; -import {colors} from '../../colors'; -import {createSearchBarTooltip} from '../../Tooltip'; -import {getAnimatedLoadingBars, log} from '../../util'; -import {ColumnCloseEvent} from '../../utilCustomEvents'; -import Taskview, {InputCohort, OutputCohort} from '../Taskview'; - +import tippy from 'tippy.js'; +import { select } from 'd3v7'; +import { EMPTY_COHORT_ID, LOADER_COHORT_ID } from '../../Cohort'; +import { colors } from '../../config/colors'; +import { getAnimatedLoadingBars, log } from '../../util'; +import { ColumnCloseEvent } from '../../base/events'; +import type Taskview from '../Taskview'; +import { CohortContext } from '../../CohortContext'; +import { ICohort, IInputCohort, IOutputCohort } from '../../app/interfaces'; +import { SearchBar } from '../SearchBar'; +import { toAttribute } from '../../Tasks'; + +function createSearchBarTooltip(elemWithTooltip: HTMLDivElement, cssClassName: string, database: string, view: string, positionStart = true) { + // start of tooltip content + const divAddAttr = document.createElement('div'); + divAddAttr.classList.add('tooltip-serachbar'); + const divText = document.createElement('div'); + divText.innerHTML = 'Add attribute columns to the input and output sides:'; + divText.classList.add('tooltip-txt'); + divAddAttr.appendChild(divText); + const divSearchBar = document.createElement('div'); + const searchBar = new SearchBar(divSearchBar, database, view, cssClassName); + divAddAttr.appendChild(divSearchBar); + + const divControls = document.createElement('div'); + const divOK = document.createElement('div'); + divOK.classList.add('okay', 'btn', 'btn-coral', 'tooltip-btn'); + divOK.innerHTML = 'Okay'; + divOK.addEventListener('click', () => { + // get options from search bar + const options = searchBar ? searchBar.getSelectedOptions() : []; + // convert options to attributes + const attributes = options.map((opt) => toAttribute(opt, database, view)); + // add attributes to taskview + CohortContext.taskview.addMultipleAttributeColumns(attributes, true, true); + // remove options and close tooltip + elemWithTooltip.click(); + }); + + divControls.classList.add('tooltip-controls'); + const divCancel = document.createElement('div'); + divCancel.classList.add('cancel', 'btn', 'btn-coral', 'tooltip-btn'); + divCancel.innerHTML = 'Cancel'; + divCancel.addEventListener('click', () => { + // remove options and close tooltip + elemWithTooltip.click(); + }); + + divControls.appendChild(divOK); + divControls.appendChild(divCancel); + divAddAttr.appendChild(divControls); + + elemWithTooltip.addEventListener('click', () => { + searchBar.removeAllSelectedOptions(); // remove all selected options form the search bar + elemWithTooltip.classList.toggle('active'); + }); + + // add the tippy tool tip + tippy(elemWithTooltip, { + content: divAddAttr, + allowHTML: true, + interactive: true, // tooltip is interactive: clickable/hoverable content + placement: positionStart ? 'top-start' : 'top-end', + appendTo: () => document.body, // add the content to the document as a child + trigger: 'click', // element has to be clicked to show the tooltip + hideOnClick: 'toggle', // the tooltip is closed when the element is clicked again + arrow: true, // show tooltip arrow + zIndex: 9000, // default z-index: 9999 (but the searchbar option container has z-index of 9001) + maxWidth: 'none', // default max. width is 350px + }); +} export abstract class AColumn { $column: HTMLDivElement; @@ -46,7 +109,7 @@ export abstract class AColumn { this.$container.dispatchEvent(new ColumnCloseEvent(this)); } - public abstract setCohorts(cohorts: Cohort[]); + public abstract setCohorts(cohorts: ICohort[]); } /** @@ -57,10 +120,12 @@ export abstract class ADataColumn extends AColumn { private dataCells; - public setCohorts(cohorts: Cohort[]) { + public setCohorts(cohorts: ICohort[]) { this.dataCells = select(this.$column) - .selectAll('div.data') + .selectAll('div.data') .data(cohorts, (d) => d.id); + + // eslint-disable-next-line @typescript-eslint/no-this-alias, @typescript-eslint/naming-convention const _thisColumn = this; // Update @@ -81,12 +146,12 @@ export abstract class ADataColumn extends AColumn { this.dataCells.exit().remove(); // Exit } - public orderCohorts(cohorts: Cohort[]) { + public orderCohorts(cohorts: ICohort[]) { this.setCohorts(cohorts); this.dataCells.order(); } - async setCell(cell: HTMLDivElement, cht: Cohort, index: number): Promise { + async setCell(cell: HTMLDivElement, cht: ICohort, index: number): Promise { log.debug('Set cell for cohort', cht.label); this.setCellStyle(cell, cht, index); @@ -101,12 +166,12 @@ export abstract class ADataColumn extends AColumn { } } - async setCellStyle(cell: HTMLDivElement, cht: Cohort, index: number): Promise { + async setCellStyle(cell: HTMLDivElement, cht: ICohort, index: number): Promise { let cellHeight = 56; // Cohort Representation + Padding + Border Top = 52px + 2*2px + 1px = 57px - if ((cht as InputCohort).outputCohorts) { + if ((cht as IInputCohort).outputCohorts) { // check chohort type -> InputCohort always has a outputCohorts array - const rows = (cht as InputCohort).outputCohorts.length; // one row for each output cohort + const rows = (cht as IInputCohort).outputCohorts.length; // one row for each output cohort cellHeight *= Math.max(rows, 1); // at least one row cellHeight += 10 - 2; // extra padding - default padding cellHeight += 1; // border @@ -117,12 +182,12 @@ export abstract class ADataColumn extends AColumn { cell.dataset.inputCohort = `${parent.dbId}`; cell.classList.remove('last-output-cohort'); cell.classList.remove('first-output-cohort'); - if ((cht as OutputCohort).isLastOutputCohort) { + if ((cht as IOutputCohort).isLastOutputCohort) { cell.classList.add('last-output-cohort'); cellHeight += 10 - 2; // extra padding - default padding cellHeight += 1; // border } - if ((cht as OutputCohort).isFirstOutputCohort) { + if ((cht as IOutputCohort).isFirstOutputCohort) { cell.classList.add('first-output-cohort'); cellHeight += 0; // margin (not part of border-box) } @@ -133,7 +198,7 @@ export abstract class ADataColumn extends AColumn { cell.classList.toggle('deselected', !selected); } - abstract setCellContent(cell: HTMLDivElement, cht: Cohort, index: number): Promise; + abstract setCellContent(cell: HTMLDivElement, cht: ICohort, index: number): Promise; } /** @@ -147,7 +212,7 @@ export class EmptyColumn extends ADataColumn { this.showLoadingAnimation = false; } - async setCellContent(cell: HTMLDivElement, cht: Cohort, index: number): Promise { + async setCellContent(cell: HTMLDivElement, cht: ICohort, index: number): Promise { // Empty } } @@ -183,7 +248,7 @@ export default class AddColumnColumn extends ADataColumn { createSearchBarTooltip(divAdd, cssClassName, database, view, onInputCohortSide); } - async setCellContent(cell: HTMLDivElement, cht: Cohort, index: number): Promise { + async setCellContent(cell: HTMLDivElement, cht: ICohort, index: number): Promise { // Empty } } diff --git a/src/Taskview/columns/AttributeColumn.ts b/src/Taskview/columns/AttributeColumn.ts index cb1de92..86ccd37 100644 --- a/src/Taskview/columns/AttributeColumn.ts +++ b/src/Taskview/columns/AttributeColumn.ts @@ -1,16 +1,12 @@ -import {select} from 'd3v7'; -import vegaEmbed from 'vega-embed'; -import { TopLevelSpec as VegaLiteSpec } from 'vega-lite'; -import { Cohort } from '../../Cohort'; -import { colors } from '../../colors'; -import { IAttribute } from '../../data/Attribute'; -import { IEqualsList, INumRange, NumRangeOperators } from '../../rest'; -import { getAnimatedLoadingBars, log } from '../../util'; -import { easyLabelFromFilter, niceName } from '../../utilLabels'; +import { select } from 'd3v7'; +import { niceName } from '../../utils/labels'; import { ADataColumn } from './AColumn'; +import { ICohort } from '../../app/interfaces'; +import type { IAttribute } from '../../data/IAttribute'; +import { Histogram } from './Histogram'; export default class AttributeColumn extends ADataColumn { - private hists: WeakMap = new WeakMap(); + private hists: WeakMap = new WeakMap(); private showOutputChtHistRef = false; @@ -96,7 +92,7 @@ export default class AttributeColumn extends ADataColumn { } updateCellContent() { - const chts = select(this.$column).selectAll('div.data').data(); + const chts = select(this.$column).selectAll('div.data').data(); for (const cht of chts) { const hist = this.hists.get(cht); hist.showReference = this.showOutputChtHistRef; @@ -135,7 +131,7 @@ export default class AttributeColumn extends ADataColumn { }); } - async setCellStyle(cell: HTMLDivElement, cht: Cohort, index: number): Promise { + async setCellStyle(cell: HTMLDivElement, cht: ICohort, index: number): Promise { super.setCellStyle(cell, cht, index); if (this.color) { @@ -153,336 +149,9 @@ export default class AttributeColumn extends ADataColumn { } // called by base class in constructor - async setCellContent(cell: HTMLDivElement, cht: Cohort, index: number): Promise { + async setCellContent(cell: HTMLDivElement, cht: ICohort, index: number): Promise { const hist = new Histogram(this.attribute, cht, this.showOutputChtHistRef, index, this.color); this.hists.set(cht, hist); cell.appendChild(hist.getNode()); } } - -class Histogram { - readonly $node: HTMLDivElement; - - readonly $loader: HTMLDivElement; - - readonly $hist: HTMLDivElement; - - vegaView: any; - - public showReference = true; - - constructor(private attribute: IAttribute, private cohort: Cohort, showReference, private index, private color) { - this.showReference = showReference; - this.$node = document.createElement('div'); - this.$node.classList.add('hist'); - - this.$loader = document.createElement('div'); - this.$loader.classList.add('loader'); // center content with flexbox - this.$loader.appendChild(getAnimatedLoadingBars()); - - this.$hist = document.createElement('div'); - - this.$node.appendChild(this.$hist); - - const that = this; - setTimeout(() => that.updateNode.bind(that)(), 0); // run async - } - - public async updateNode() { - this.$hist.remove(); - try { - if (!this.cohort.hasfilterConflict()) { - this.$node.appendChild(this.$loader); - // get hist data of attribute for cohort - let data: { bin: string; count: number }[]; - try { - data = await this.attribute.getHist(this.cohort.dbId, this.cohort.filters); - } catch (e) { - log.error('get hist failed', e); - this.$loader.remove(); - this.$node.classList.add('text'); - this.$hist.innerHTML = ` -

- - Request timeout. -

- `; - this.$node.appendChild(this.$hist); - return; - } - - const notZeroData = data.filter((d) => d.count > 0); // filter only for categories/bins with count bigger 0 - let showText = false; - // show only text when 1 bin and not numerical attribute or when numerical attribute only for one bin if it is for null - if ( - this.attribute.type !== 'number' || - (this.attribute.type === 'number' && notZeroData.length === 1 && (notZeroData[0].bin === 'null' || notZeroData[0].bin === null)) - ) { - showText = notZeroData.length === 1; // show text when only one category/bin with count bigger 0 - } - - const chtSize = await this.cohort.size; - // -> size = 0: show only line in data cell with vega vis (all bins/categories have count 0) - - // check if reference should be shown and - // if the size of the current cohort is bigger then 0 - if (this.showReference && chtSize > 0) { - if (this.cohort.getCohortParents().length > 0) { - // get parent cohort - const parentCht = this.cohort.getCohortParents()[0]; - // get hist data of attribtue for parent cohort - const parentData: { bin: string; count: number }[] = await this.attribute.getHist(parentCht.dbId, parentCht.filters); - const notZeroParentData = parentData.filter((d) => d.count > 0); // filter only for categories/bins with count bigger 0 - const showParentText = notZeroParentData.length === 1; // show text when only one category/bin with count bigger 0 - const vegaData = { - data, - parentData, - parentColor: parentCht.colorTaskView, - }; - if (showParentText) { - const { bin } = notZeroParentData[0]; - // TODO labels - // const text = this.formatText(bin); - const text = this.formatText(bin, this.cohort.values); - this.$node.classList.add('text'); - this.$hist.innerHTML = text; - } else { - // show histogram with reference - this.$node.classList.remove('text'); - vegaEmbed(this.$hist, this.getMinimalVegaSpecWithRef(vegaData), { actions: false, renderer: 'svg' }).then((result) => { - this.vegaView = result.view; - }); - } - } - } else { - // when no reference should be shown (is also the case for the input cohort side) - // check if only one category/bin has values - if (showText) { - // show only text - const { bin } = notZeroData[0]; - // TODO labels - // const text = this.formatText(bin); - this.$node.classList.add('text'); - const text = this.formatText(bin, this.cohort.values); - this.$hist.innerHTML = text; - } else { - // show histogram - this.$node.classList.remove('text'); - vegaEmbed(this.$hist, this.getMinimalVegaSpec(data), { actions: false, renderer: 'svg' }).then((result) => { - this.vegaView = result.view; - }); - } - } - - this.$loader.remove(); - this.$node.appendChild(this.$hist); - } else { - throw new Error('Can not show histogram due to filter contradiction'); - } - } catch (e) { - log.error('Cant show histogram', e); - - this.$loader.remove(); - this.$node.classList.add('text'); - this.$hist.innerHTML = ` -

- - Can not display histogram. -

- `; - this.$node.appendChild(this.$hist); - } - } - - // TODO labels - // private formatText(value: string): string { - private formatText(value: string, filters: Array): string { - if (value === 'null' || value === null || value === undefined) { - value = `Missing Values`; - } - let text = String(value); // turn boolean categories into strings - - if (text.indexOf('(') >= 0 || text.indexOf('[') >= 0) { - const values = text.split(', '); - const params = { - firstOp: values[0][0], - firstValue: Number(values[0].substring(1)), - secondOp: values[1][values[1].length - 1], - // TODO labels - // secondValue: Number(values[1].substring(0, values[1].length - 2)) - secondValue: Number(values[1].substring(0, values[1].length - 1)), - }; - // TODO lables - // text = labelFromRanges(params.firstOp === '(' ? '(' : '[', params.firstValue, params.secondValue, params.secondOp === ')' ? ')' : ']', this.attribute); - const range: INumRange = { - operatorOne: params.firstOp === '(' ? NumRangeOperators.gt : NumRangeOperators.gte, - valueOne: params.firstValue, - operatorTwo: params.secondOp === ')' ? NumRangeOperators.lt : NumRangeOperators.lte, - valueTwo: params.secondValue, - }; - - text = easyLabelFromFilter(range, this.attribute.label); - } else { - text = niceName(text); - } - return text; - } - - public getNode() { - return this.$node; - } - - public getMinimalVegaSpec(data): VegaLiteSpec { - let sort: any = 'ascending'; - if (this.attribute.type === 'number') { - sort = { field: 'index' }; - } - return { - $schema: 'https://vega.github.io/schema/vega-lite/v5.json', - width: 'container', // responsive width - height: 50, // responsive height - background: '#ffffff00', // set visualization background to white and opacity 0 -> https://vega.github.io/vega-lite/docs/spec.html#example-background - autosize: { type: 'fit', contains: 'padding' }, // plots fit a bit better, if though they are specified as responsive - data: { values: data }, - mark: { - type: 'bar', - tooltip: true, - }, - encoding: { - x: { - field: 'bin', - type: 'nominal', - axis: { - title: null, // we will have the title in the column header - labels: false, // no space for labels - ticks: false, - }, - sort, - }, - y: { - field: 'count', - type: 'quantitative', - axis: null, // no axis, no title, labels, no grid - }, - color: { - field: 'this_does_not_exist', // field is necessary but does not have to exist - type: 'nominal', // type is also necessary, nominal as we have only one category (or none :) ) - scale: { - range: [this.cohort.colorTaskView || colors.barColor], // [this.color ? Cat16.get(this.index) : colors.barColor] - }, - legend: null, // no legend - }, - tooltip: [ - { field: 'bin', type: 'nominal' }, - { field: 'count', type: 'quantitative' }, - ], - }, - config: { - view: { - stroke: 'transparent', // https://vega.github.io/vega-lite/docs/spec.html#view-background - }, - }, - params: [ - { - name: 'highlight', - select: { - type: 'point', - on: 'mouseover', - clear: 'mouseout', - }, - }, - ], - }; - } - - public getMinimalVegaSpecWithRef(data): VegaLiteSpec { - let sort: any = 'ascending'; - if (this.attribute.type === 'number') { - sort = { field: 'index' }; - } - return { - $schema: 'https://vega.github.io/schema/vega-lite/v5.json', - width: 'container', // responsive width - height: 50, // responsive height - background: '#ffffff00', // set visualization background to white and opacity 0 -> https://vega.github.io/vega-lite/docs/spec.html#example-background - autosize: { type: 'fit', contains: 'padding' }, // plots fit a bit better, if though they are specified as responsive - datasets: { - parentData: data.parentData, - data: data.data, - }, - layer: [ - { - // layer 1: input cohort reference data - data: { name: 'parentData' }, - mark: { - type: 'bar', - tooltip: true, - }, - encoding: { - x: { - field: 'bin', - type: 'nominal', - axis: { - title: null, // we will have the title in the column header - labels: false, // no space for labels - ticks: false, - }, - sort, - }, - y: { - field: 'count', - type: 'quantitative', - axis: null, // no axis, no title, labels, no grid - }, - fill: { - value: data.parentColor, - legend: null, // no legend - }, - tooltip: [ - { field: 'bin', type: 'nominal' }, - { field: 'count', type: 'quantitative' }, - ], - }, - }, - { - // layer 2: output cohort data - data: { name: 'data' }, - mark: { - type: 'bar', - tooltip: true, - }, - encoding: { - x: { - field: 'bin', - type: 'nominal', - axis: { - title: null, // we will have the title in the column header - labels: false, // no space for labels - ticks: false, - }, - sort, - }, - y: { - field: 'count', - type: 'quantitative', - axis: null, // no axis, no title, labels, no grid - }, - fill: { - value: colors.barColor, - legend: null, // no legend - }, - tooltip: [ - { field: 'bin', type: 'nominal' }, - { field: 'count', type: 'quantitative' }, - ], - }, - }, - ], - config: { - view: { - stroke: 'transparent', // https://vega.github.io/vega-lite/docs/spec.html#view-background - }, - }, - }; - } -} diff --git a/src/Taskview/columns/CohortColumn.ts b/src/Taskview/columns/CohortColumn.ts index 4c6d58d..cbcbe01 100644 --- a/src/Taskview/columns/CohortColumn.ts +++ b/src/Taskview/columns/CohortColumn.ts @@ -1,9 +1,9 @@ -import {select} from 'd3v7'; -import {Cohort} from '../../Cohort'; -import {OnboardingManager} from '../../OnboardingManager'; -import {SortType} from '../../util'; -import {ColumnSortEvent} from '../../utilCustomEvents'; -import {ADataColumn} from './AColumn'; +import { select } from 'd3v7'; +import { OnboardingManager } from '../../OnboardingManager'; +import { SortType } from '../../util'; +import { ColumnSortEvent } from '../../base/events'; +import { ADataColumn } from './AColumn'; +import { ICohort } from '../../app/interfaces'; /** * Displays cohorts with their given representation as a column @@ -29,7 +29,7 @@ export abstract class ACohortColumn extends ADataColumn { this.addSortButton(); } - async setCellContent(cell: HTMLDivElement, cht: Cohort): Promise { + async setCellContent(cell: HTMLDivElement, cht: ICohort): Promise { const clone = cht.representation.getClone(); cell.appendChild(clone); // Using appendChild (instead of innerHTML) is important to keep track of 'checked' attributes and others cell.style.padding = '2px'; @@ -77,7 +77,7 @@ export class InputCohortColumn extends ACohortColumn { this.$column.classList.add('first'); } - setCohorts(cohorts: Cohort[]) { + setCohorts(cohorts: ICohort[]) { if (this.init && cohorts.length > 0) { this.init = false; OnboardingManager.addTip('input', this.$header); @@ -91,7 +91,7 @@ export class InputCohortColumn extends ACohortColumn { } export class OutputCohortColumn extends ACohortColumn { - cohorts: Cohort[]; + cohorts: ICohort[]; init = true; @@ -100,7 +100,7 @@ export class OutputCohortColumn extends ACohortColumn { this.$column.classList.add('last'); } - public setCohorts(cohorts: Cohort[]) { + public setCohorts(cohorts: ICohort[]) { this.cohorts = cohorts; super.setCohorts(cohorts); diff --git a/src/Taskview/columns/Histogram.ts b/src/Taskview/columns/Histogram.ts new file mode 100644 index 0000000..3d4f4c6 --- /dev/null +++ b/src/Taskview/columns/Histogram.ts @@ -0,0 +1,334 @@ +import vegaEmbed from 'vega-embed'; +import { TopLevelSpec as VegaLiteSpec } from 'vega-lite'; +import { colors } from '../../config/colors'; +import { IAttribute } from '../../data'; +import { INumRange, IEqualsList, NumRangeOperators } from '../../base'; +import { getAnimatedLoadingBars, log } from '../../util'; +import { easyLabelFromFilter, niceName } from '../../utils/labels'; +import { ICohort } from '../../app/interfaces'; + +export class Histogram { + readonly $node: HTMLDivElement; + + readonly $loader: HTMLDivElement; + + readonly $hist: HTMLDivElement; + + vegaView: any; + + public showReference = true; + + constructor(private attribute: IAttribute, private cohort: ICohort, showReference, private index, private color) { + this.showReference = showReference; + this.$node = document.createElement('div'); + this.$node.classList.add('hist'); + + this.$loader = document.createElement('div'); + this.$loader.classList.add('loader'); // center content with flexbox + this.$loader.appendChild(getAnimatedLoadingBars()); + + this.$hist = document.createElement('div'); + + this.$node.appendChild(this.$hist); + + // eslint-disable-next-line @typescript-eslint/no-this-alias + const that = this; + setTimeout(() => that.updateNode.bind(that)(), 0); // run async + } + + public async updateNode() { + this.$hist.remove(); + try { + if (!this.cohort.hasfilterConflict()) { + this.$node.appendChild(this.$loader); + // get hist data of attribute for cohort + let data: { bin: string; count: number }[]; + try { + data = await this.attribute.getHist(this.cohort.dbId, this.cohort.filters); + } catch (e) { + log.error('get hist failed', e); + this.$loader.remove(); + this.$node.classList.add('text'); + this.$hist.innerHTML = ` +

+ + Request timeout. +

+ `; + this.$node.appendChild(this.$hist); + return; + } + + const notZeroData = data.filter((d) => d.count > 0); // filter only for categories/bins with count bigger 0 + let showText = false; + // show only text when 1 bin and not numerical attribute or when numerical attribute only for one bin if it is for null + if ( + this.attribute.type !== 'number' || + (this.attribute.type === 'number' && notZeroData.length === 1 && (notZeroData[0].bin === 'null' || notZeroData[0].bin === null)) + ) { + showText = notZeroData.length === 1; // show text when only one category/bin with count bigger 0 + } + + const chtSize = await this.cohort.size; + // -> size = 0: show only line in data cell with vega vis (all bins/categories have count 0) + + // check if reference should be shown and + // if the size of the current cohort is bigger then 0 + if (this.showReference && chtSize > 0) { + if (this.cohort.getCohortParents().length > 0) { + // get parent cohort + const parentCht = this.cohort.getCohortParents()[0]; + // get hist data of attribtue for parent cohort + const parentData: { bin: string; count: number }[] = await this.attribute.getHist(parentCht.dbId, parentCht.filters); + const notZeroParentData = parentData.filter((d) => d.count > 0); // filter only for categories/bins with count bigger 0 + const showParentText = notZeroParentData.length === 1; // show text when only one category/bin with count bigger 0 + const vegaData = { + data, + parentData, + parentColor: parentCht.colorTaskView, + }; + if (showParentText) { + const { bin } = notZeroParentData[0]; + // TODO labels + // const text = this.formatText(bin); + const text = this.formatText(bin, this.cohort.values); + this.$node.classList.add('text'); + this.$hist.innerHTML = text; + } else { + // show histogram with reference + this.$node.classList.remove('text'); + vegaEmbed(this.$hist, this.getMinimalVegaSpecWithRef(vegaData), { actions: false, renderer: 'svg' }).then((result) => { + this.vegaView = result.view; + }); + } + } + } else if (showText) { + // when no reference should be shown (is also the case for the input cohort side) + // check if only one category/bin has values + // show only text + const { bin } = notZeroData[0]; + // TODO labels + // const text = this.formatText(bin); + this.$node.classList.add('text'); + const text = this.formatText(bin, this.cohort.values); + this.$hist.innerHTML = text; + } else { + // show histogram + this.$node.classList.remove('text'); + vegaEmbed(this.$hist, this.getMinimalVegaSpec(data), { actions: false, renderer: 'svg' }).then((result) => { + this.vegaView = result.view; + }); + } + + this.$loader.remove(); + this.$node.appendChild(this.$hist); + } else { + throw new Error('Can not show histogram due to filter contradiction'); + } + } catch (e) { + log.error('Cant show histogram', e); + + this.$loader.remove(); + this.$node.classList.add('text'); + this.$hist.innerHTML = ` +

+ + Can not display histogram. +

+ `; + this.$node.appendChild(this.$hist); + } + } + + // TODO labels + // private formatText(value: string): string { + private formatText(value: string, filters: Array): string { + if (value === 'null' || value === null || value === undefined) { + value = `Missing Values`; + } + let text = String(value); // turn boolean categories into strings + + if (text.indexOf('(') >= 0 || text.indexOf('[') >= 0) { + const values = text.split(', '); + const params = { + firstOp: values[0][0], + firstValue: Number(values[0].substring(1)), + secondOp: values[1][values[1].length - 1], + // TODO labels + // secondValue: Number(values[1].substring(0, values[1].length - 2)) + secondValue: Number(values[1].substring(0, values[1].length - 1)), + }; + // TODO lables + // text = labelFromRanges(params.firstOp === '(' ? '(' : '[', params.firstValue, params.secondValue, params.secondOp === ')' ? ')' : ']', this.attribute); + const range: INumRange = { + operatorOne: params.firstOp === '(' ? NumRangeOperators.gt : NumRangeOperators.gte, + valueOne: params.firstValue, + operatorTwo: params.secondOp === ')' ? NumRangeOperators.lt : NumRangeOperators.lte, + valueTwo: params.secondValue, + }; + + text = easyLabelFromFilter(range, this.attribute.label); + } else { + text = niceName(text); + } + return text; + } + + public getNode() { + return this.$node; + } + + public getMinimalVegaSpec(data): VegaLiteSpec { + let sort: any = 'ascending'; + if (this.attribute.type === 'number') { + sort = { field: 'index' }; + } + return { + $schema: 'https://vega.github.io/schema/vega-lite/v5.json', + width: 'container', // responsive width + height: 50, // responsive height + background: '#ffffff00', // set visualization background to white and opacity 0 -> https://vega.github.io/vega-lite/docs/spec.html#example-background + autosize: { type: 'fit', contains: 'padding' }, // plots fit a bit better, if though they are specified as responsive + data: { values: data }, + mark: { + type: 'bar', + tooltip: true, + }, + encoding: { + x: { + field: 'bin', + type: 'nominal', + axis: { + title: null, // we will have the title in the column header + labels: false, // no space for labels + ticks: false, + }, + sort, + }, + y: { + field: 'count', + type: 'quantitative', + axis: null, // no axis, no title, labels, no grid + }, + color: { + field: 'this_does_not_exist', // field is necessary but does not have to exist + type: 'nominal', // type is also necessary, nominal as we have only one category (or none :) ) + scale: { + range: [this.cohort.colorTaskView || colors.barColor], // [this.color ? Cat16.get(this.index) : colors.barColor] + }, + legend: null, // no legend + }, + tooltip: [ + { field: 'bin', type: 'nominal' }, + { field: 'count', type: 'quantitative' }, + ], + }, + config: { + view: { + stroke: 'transparent', // https://vega.github.io/vega-lite/docs/spec.html#view-background + }, + }, + params: [ + { + name: 'highlight', + select: { + type: 'point', + on: 'mouseover', + clear: 'mouseout', + }, + }, + ], + }; + } + + public getMinimalVegaSpecWithRef(data): VegaLiteSpec { + let sort: any = 'ascending'; + if (this.attribute.type === 'number') { + sort = { field: 'index' }; + } + return { + $schema: 'https://vega.github.io/schema/vega-lite/v5.json', + width: 'container', // responsive width + height: 50, // responsive height + background: '#ffffff00', // set visualization background to white and opacity 0 -> https://vega.github.io/vega-lite/docs/spec.html#example-background + autosize: { type: 'fit', contains: 'padding' }, // plots fit a bit better, if though they are specified as responsive + datasets: { + parentData: data.parentData, + data: data.data, + }, + layer: [ + { + // layer 1: input cohort reference data + data: { name: 'parentData' }, + mark: { + type: 'bar', + tooltip: true, + }, + encoding: { + x: { + field: 'bin', + type: 'nominal', + axis: { + title: null, // we will have the title in the column header + labels: false, // no space for labels + ticks: false, + }, + sort, + }, + y: { + field: 'count', + type: 'quantitative', + axis: null, // no axis, no title, labels, no grid + }, + fill: { + value: data.parentColor, + legend: null, // no legend + }, + tooltip: [ + { field: 'bin', type: 'nominal' }, + { field: 'count', type: 'quantitative' }, + ], + }, + }, + { + // layer 2: output cohort data + data: { name: 'data' }, + mark: { + type: 'bar', + tooltip: true, + }, + encoding: { + x: { + field: 'bin', + type: 'nominal', + axis: { + title: null, // we will have the title in the column header + labels: false, // no space for labels + ticks: false, + }, + sort, + }, + y: { + field: 'count', + type: 'quantitative', + axis: null, // no axis, no title, labels, no grid + }, + fill: { + value: colors.barColor, // TODO: check if this value actually exists + legend: null, // no legend + }, + tooltip: [ + { field: 'bin', type: 'nominal' }, + { field: 'count', type: 'quantitative' }, + ], + }, + }, + ], + config: { + view: { + stroke: 'transparent', // https://vega.github.io/vega-lite/docs/spec.html#view-background + }, + }, + }; + } +} diff --git a/src/Taskview/columns/NumberColumn.ts b/src/Taskview/columns/NumberColumn.ts index b29908a..23d38b6 100644 --- a/src/Taskview/columns/NumberColumn.ts +++ b/src/Taskview/columns/NumberColumn.ts @@ -1,6 +1,6 @@ -import {format as d3Format} from 'd3v7'; -import {Cohort} from '../../Cohort'; -import {ADataColumn} from './AColumn'; +import { format as d3Format } from 'd3v7'; +import { ICohort } from '../../app/interfaces'; +import { ADataColumn } from './AColumn'; export default class NumberColumn extends ADataColumn { constructor($container: HTMLDivElement) { @@ -8,12 +8,12 @@ export default class NumberColumn extends ADataColumn { this.$column.classList.add('first', 'number'); } - async setCellStyle(cell: HTMLDivElement, cht: Cohort, index: number): Promise { + async setCellStyle(cell: HTMLDivElement, cht: ICohort, index: number): Promise { super.setCellStyle(cell, cht, index); this.setCellContent(cell, cht, index); } - async setCellContent(cell: HTMLDivElement, cht: Cohort, index: number): Promise { + async setCellContent(cell: HTMLDivElement, cht: ICohort, index: number): Promise { while (cell.firstChild) { cell.removeChild(cell.firstChild); } diff --git a/src/Taskview/columns/PrevalenceColumn.ts b/src/Taskview/columns/PrevalenceColumn.ts index 0bc341c..c9d6be7 100644 --- a/src/Taskview/columns/PrevalenceColumn.ts +++ b/src/Taskview/columns/PrevalenceColumn.ts @@ -1,21 +1,10 @@ import vegaEmbed from 'vega-embed'; import { TopLevelSpec as VegaLiteSpec } from 'vega-lite'; -import { Cohort } from '../../Cohort'; -import { colors } from '../../colors'; +import { ICohort } from '../../app/interfaces'; +import { colors } from '../../config/colors'; import { getAnimatedLoadingBars } from '../../util'; import { ADataColumn } from './AColumn'; -export default class PrevalenceColumn extends ADataColumn { - constructor(private reference: Cohort, $container: HTMLDivElement) { - super(`% [${reference.label}]`, $container); - this.$column.classList.add('prevalence'); - } - - async setCellContent(cell: HTMLDivElement, cht: Cohort): Promise { - cell.appendChild(new PrevalenceBar(cht, this.reference).getNode()); - } -} - class PrevalenceBar { readonly $node: HTMLDivElement; @@ -23,7 +12,7 @@ class PrevalenceBar { readonly $hist: HTMLDivElement; - constructor(private cht: Cohort, private reference: Cohort) { + constructor(private cht: ICohort, private reference: ICohort) { this.$node = document.createElement('div'); this.$node.classList.add('hist'); @@ -35,6 +24,7 @@ class PrevalenceBar { this.$node.appendChild(this.$hist); + // eslint-disable-next-line @typescript-eslint/no-this-alias const that = this; setTimeout(() => that.updateNode.bind(that)(), 0); // run async } @@ -115,3 +105,14 @@ class PrevalenceBar { }; } } + +export default class PrevalenceColumn extends ADataColumn { + constructor(private reference: ICohort, $container: HTMLDivElement) { + super(`% [${reference.label}]`, $container); + this.$column.classList.add('prevalence'); + } + + async setCellContent(cell: HTMLDivElement, cht: ICohort): Promise { + cell.appendChild(new PrevalenceBar(cht, this.reference).getNode()); + } +} diff --git a/src/Taskview/columns/index.ts b/src/Taskview/columns/index.ts index 49ce44f..65ed462 100644 --- a/src/Taskview/columns/index.ts +++ b/src/Taskview/columns/index.ts @@ -1,8 +1,5 @@ export * from './AColumn'; -export * from './AttributeColumn'; export { default as AttributeColumn } from './AttributeColumn'; export * from './CohortColumn'; -export * from './NumberColumn'; export { default as NumberColumn } from './NumberColumn'; -export * from './PrevalenceColumn'; export { default as PrevalenceColumn } from './PrevalenceColumn'; diff --git a/src/Taskview/index.ts b/src/Taskview/index.ts index f8de926..dab705a 100644 --- a/src/Taskview/index.ts +++ b/src/Taskview/index.ts @@ -3,7 +3,5 @@ export * from './tasks'; export * from './visualizations'; export * from './SearchBar'; -export * from './SearchColumn'; export { default as SearchColumn } from './SearchColumn'; -export * from './Taskview'; export { default as Taskview } from './Taskview'; diff --git a/src/Taskview/interfaces.ts b/src/Taskview/interfaces.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/Taskview/tasks/ATask.ts b/src/Taskview/tasks/ATask.ts index 45c38c0..e77f3b4 100644 --- a/src/Taskview/tasks/ATask.ts +++ b/src/Taskview/tasks/ATask.ts @@ -1,7 +1,7 @@ -import {select, Selection} from 'd3v7'; -import {ICohort} from '../../CohortInterfaces'; -import {IAttribute} from '../../data/Attribute'; -import {OnboardingManager} from '../../OnboardingManager'; +import { select, Selection } from 'd3v7'; +import { ICohort } from '../../app/interfaces'; +import { IAttribute } from '../../data/IAttribute'; +import { OnboardingManager } from '../../OnboardingManager'; export const TASK_CLOSE_EVENT_TYPE = 'task:close'; @@ -33,6 +33,7 @@ export abstract class ATask { abstract showSearchBar(): boolean; show(columnHeader: HTMLDivElement, container: HTMLDivElement, attributes: IAttribute[], cohorts: ICohort[]) { + // eslint-disable-next-line @typescript-eslint/no-this-alias const task = this; select(container).selectAll('*').remove(); select(columnHeader).selectAll('.task-title').remove(); @@ -56,6 +57,7 @@ export abstract class ATask { ${this.label}`, ) .on('click', function () { + // eslint-disable-next-line @typescript-eslint/no-this-alias const clickedBtn = this; clickedBtn.dispatchEvent(new TaskCloseEvent(task)); }); diff --git a/src/Taskview/tasks/Compare.ts b/src/Taskview/tasks/Compare.ts index eea686d..ee5a899 100644 --- a/src/Taskview/tasks/Compare.ts +++ b/src/Taskview/tasks/Compare.ts @@ -1,17 +1,19 @@ +/* eslint-disable @typescript-eslint/no-this-alias */ +/* eslint-disable @typescript-eslint/no-use-before-define */ /* ***************************************************************************** * Caleydo - Visualization for Molecular Biology - http://caleydo.org * Copyright (c) The Caleydo Team. All rights reserved. * Licensed under the new BSD license, available at http://caleydo.org/license **************************************************************************** */ - -import {hsl, scaleLinear, select, Selection} from 'd3v7'; +import { hsl, scaleLinear, select, Selection } from 'd3v7'; import * as d3v3 from 'd3v3'; -import {IMeasureResult, IMeasureVisualization, ISetParameters, ISimilarityMeasure, MethodManager, SCOPE, Type, WorkerManager} from 'tourdino'; -import {Cohort} from '../../Cohort'; -import {Attribute, IAttribute} from '../../data/Attribute'; -import {log} from '../../util'; -import {ATask} from './ATask'; +import { IMeasureResult, ISetParameters, ISimilarityMeasure, MethodManager, SCOPE, Type, WorkerManager } from 'tourdino'; +import { Attribute } from '../../data/Attribute'; +import { log } from '../../util'; +import { ATask } from './ATask'; +import { ICohort } from '../../app/interfaces'; +import type { IAttribute } from '../../data/IAttribute'; export class Compare extends ATask { public label = `Compare`; @@ -22,9 +24,9 @@ export class Compare extends ATask { attributes: IAttribute[]; - cohorts: Cohort[]; + cohorts: ICohort[]; - supports(attributes: IAttribute[], cohorts: Cohort[]) { + supports(attributes: IAttribute[], cohorts: ICohort[]) { return cohorts.length > 0; } @@ -32,7 +34,7 @@ export class Compare extends ATask { return true; } - async show(columnHeader: HTMLDivElement, container: HTMLDivElement, attributes: IAttribute[], cohorts: Cohort[]) { + async show(columnHeader: HTMLDivElement, container: HTMLDivElement, attributes: IAttribute[], cohorts: ICohort[]) { super.show(columnHeader, container, attributes, cohorts); this.attributes = attributes; this.cohorts = cohorts; @@ -79,12 +81,12 @@ export class Compare extends ATask { const colHeadsCht = this.body .select('thead tr') .selectAll('th.head') - .data(this.cohorts, (cht: Cohort) => cht.id); + .data(this.cohorts, (cht: ICohort) => cht.id); const colHeadsChtSpan = colHeadsCht.enter().append('th').attr('class', 'head rotate').append('div').append('span').append('span'); // th.head are the column headers const that = this; // for the function below - const updateTableBody = (bodyData: Array>>, timestamp: string) => { - if (that.body.attr('data-timestamp') !== timestamp) { + const updateTableBody = (bodyData: Array>>, timestampArg: string) => { + if (that.body.attr('data-timestamp') !== timestampArg) { return; // skip outdated result } @@ -114,16 +116,17 @@ export class Compare extends ATask { // Set colheads in thead colHeadsChtSpan.html((d) => `${d.label}`); - colHeadsChtSpan.each(function (d: Cohort) { + colHeadsChtSpan.each(function (cohort: ICohort) { const parent = select(this).node().parentNode as HTMLElement; // parent span-element - select(parent).style('background-color', (d) => (d as Cohort).colorTaskView); + select(parent).style('background-color', (d: ICohort) => d.colorTaskView); let color = '#333333'; - if (d && d.colorTaskView && 'transparent' !== d.colorTaskView && hsl(d.colorTaskView).l < 0.5) { //transparent has lightness of zero + if (cohort && cohort.colorTaskView && cohort.colorTaskView !== 'transparent' && hsl(cohort.colorTaskView).l < 0.5) { + // transparent has lightness of zero color = 'white'; } select(parent.parentNode as HTMLElement) .style('color', color) - .attr('title', (d: Cohort) => `${d.label}`); + .attr('title', (d: ICohort) => `${d.label}`); }); // set data in tbody @@ -197,7 +200,7 @@ export class Compare extends ATask { * @param update */ async getTableBody( - cohorts: Cohort[], + cohorts: ICohort[], attributes: Attribute[], scaffold: boolean, update: (bodyData: IScoreCell[][][]) => void, @@ -220,6 +223,8 @@ export class Compare extends ATask { for (const [rowIndex, rowCht] of cohorts.entries()) { // Get the data of 'attr' for the rows inside 'rowCht' + // TODO: fix me + // eslint-disable-next-line no-await-in-loop const rowData = (await attr.getData(rowCht.dbId)).map((item) => item[attr.dataKey]); for (const [colIndex, colCht] of cohorts.entries()) { const colIndexOffset = rowIndex === 0 ? 2 : 1; // Two columns if the attribute label is in the same line, (otherwise 1 (because rowspan)) @@ -230,6 +235,8 @@ export class Compare extends ATask { } else if (rowIndex4col[rowIndex] >= 0 && rowIndex4col[colIndex] >= 0 && rowIndex4col[colIndex] < rowIndex) { // the cht is also part of the colGroups array, and the colGrp is one of the previous rowGroups --> i.e. already calculated in a table row above the current one } else { + // TODO: fix me + // eslint-disable-next-line no-await-in-loop const colData = (await attr.getData(colCht.dbId)).map((item) => item[attr.dataKey]); const setParameters = { setA: rowData, @@ -283,7 +290,7 @@ export class Compare extends ATask { return data; // then return the data } - prepareDataArray(cohorts: Cohort[], attributes: Attribute[]) { + prepareDataArray(cohorts: ICohort[], attributes: Attribute[]) { if (cohorts.length === 0 || attributes.length === 0) { return []; // return empty array, will cause an empty table } @@ -316,6 +323,7 @@ export class Compare extends ATask { } toScoreCell(score: IMeasureResult, measure: ISimilarityMeasure, setParameters: ISetParameters): IScoreCell { + // eslint-disable-next-line @typescript-eslint/no-use-before-define let color = score2color(score.pValue); let cellLabel = score.pValue.toFixed(3); @@ -383,7 +391,8 @@ export class Compare extends ATask { const category = rowCategories.pop(); const isColTask = category === row; const cellData = select(tableCell).datum() as IScoreCell; - const scoreValue = typeof cellData.score.scoreValue === 'number' && !isNaN(cellData.score.scoreValue) ? cellData.score.scoreValue.toFixed(3) : 'n/a'; + const scoreValue = + typeof cellData.score.scoreValue === 'number' && !Number.isNaN(cellData.score.scoreValue) ? cellData.score.scoreValue.toFixed(3) : 'n/a'; let scorePvalue: string | number = cellData.score.pValue; if (scorePvalue === -1) { scorePvalue = 'n/a'; @@ -545,7 +554,7 @@ export class Compare extends ATask { detailSetInfo.append('span').html(`${setBLabel} `).append('span').text(`[${measureResult.setSizeB}]`); // test value + p-value - const scoreValue = typeof measureResult.scoreValue === 'number' && !isNaN(measureResult.scoreValue) ? measureResult.scoreValue.toFixed(3) : 'n/a'; + const scoreValue = typeof measureResult.scoreValue === 'number' && !Number.isNaN(measureResult.scoreValue) ? measureResult.scoreValue.toFixed(3) : 'n/a'; const pValue = measureResult.pValue === -1 ? 'n/a' : (measureResult.pValue as number).toExponential(3); const detailInfoValues = divDetailInfo.append('div').classed('detailDiv', true); // .text(`Test-Value: ${scoreValue}, p-Value: ${pValue}`); @@ -744,7 +753,8 @@ interface IHighlightData { export function textColor4Background(backgroundColor: string) { let color = '#333333'; - if ('transparent' !== backgroundColor && hsl(backgroundColor).l < 0.5) { //transparent has lightness of zero + if (backgroundColor !== 'transparent' && hsl(backgroundColor).l < 0.5) { + // transparent has lightness of zero color = 'white'; } @@ -757,7 +767,9 @@ export function score2color(score: number): { background: string; foreground: st if (score <= 0.05) { // log.debug('bg color cahnge') - const calcColor = scaleLinear().domain([0, 0.05]).range(['#000000', '#FFFFFF']); + const calcColor = scaleLinear() + .domain([0, 0.05]) + .range(['#000000', '#FFFFFF']); background = calcColor(score).toString(); foreground = textColor4Background(background); diff --git a/src/Taskview/tasks/Details.ts b/src/Taskview/tasks/Details.ts index d1f37b8..385fac9 100644 --- a/src/Taskview/tasks/Details.ts +++ b/src/Taskview/tasks/Details.ts @@ -1,15 +1,14 @@ import * as aq from 'arquero'; -import {select} from 'd3v7'; +import { select } from 'd3v7'; import * as LineUpJS from 'lineupjs'; -import { Cohort } from '../../Cohort'; -import { ICohort } from '../../CohortInterfaces'; -import { colors } from '../../colors'; -import { IAttribute } from '../../data/Attribute'; -import { getCohortData } from '../../rest'; -import { CohortColorSchema, getAnimatedLoadingText } from '../../util'; -import { getIdTypeFromCohort } from '../../utilIdTypes'; +import { ICohort } from '../../app/interfaces'; +import { colors, CoralColorSchema } from '../../config/colors'; +import { getCohortData } from '../../base/rest'; +import { getAnimatedLoadingText } from '../../util'; +import { getIdTypeFromCohort } from '../../config/entities'; import { DATA_LABEL } from '../visualizations'; import { ATask } from './ATask'; +import type { IAttribute } from '../../data/IAttribute'; export class Details extends ATask { public label = `Inspect Items`; @@ -43,7 +42,7 @@ export class Details extends ATask { this.$lineUpContainer.insertAdjacentElement('beforeend', getAnimatedLoadingText('data')); select(columnHeader).selectAll('.export').remove(); - const data = await this.getData(attributes, cohorts as Cohort[]); + const data = await this.getData(attributes, cohorts as ICohort[]); if (eventId !== this.eventID) { return; } @@ -62,19 +61,18 @@ export class Details extends ATask { } } - async getData(attributes: IAttribute[], cohorts: Cohort[]) { - const idType = getIdTypeFromCohort(cohorts[0] as Cohort); + async getData(attributes: IAttribute[], cohorts: ICohort[]) { + const idType = getIdTypeFromCohort(cohorts[0] as ICohort); this._entityName = idType.entityName; - const dataPromises = cohorts.map((cht) => { - const promise = new Promise(async (resolve, reject) => { + const dataPromises = cohorts.map(async (cht) => { + const promise = new Promise((resolve, reject) => { const chtDataPromises = attributes.map((attr) => attr.getData(cht.dbId)); if (attributes.length === 0) { // If Lineup is empty, add entityName as single attribute to be able to show something chtDataPromises.push(getCohortData({ cohortId: cht.dbId, attribute: idType.entityName })); } - try { - const chtData = await Promise.all(chtDataPromises); // array with one entry per attribute, which contains an array with one value for every item in the cohort + Promise.all(chtDataPromises).then((chtData) => { let joinedData = aq.from(chtData[0]); for (let i = 1; i < chtData.length; i++) { joinedData = joinedData.join_full(aq.from(chtData[i])); @@ -82,9 +80,7 @@ export class Details extends ATask { const labelTable = aq.table({ [DATA_LABEL]: [[`${cht.dbId}`]], [`id_${cht.dbId}`]: ['true'] }); joinedData = joinedData.join_left(labelTable, (data, label) => true); resolve(joinedData.objects()); - } catch (e) { - reject(e); - } + }); }); return promise; }); @@ -112,7 +108,7 @@ export class Details extends ATask { builder.column(LineUpJS.buildStringColumn(this._entityName).label('Id').width(120)).column( LineUpJS.buildCategoricalColumn( DATA_LABEL, - cohorts.map((cht) => ({ name: `${cht.dbId}`, label: cht.label, color: (cht as Cohort).colorTaskView })), + cohorts.map((cht) => ({ name: `${cht.dbId}`, label: cht.label, color: (cht as ICohort).colorTaskView })), ) .renderer('catheatmap', 'categorical') .asSet(), @@ -143,7 +139,7 @@ export class Details extends ATask { getCategoryColorsForColumn(mergedDataArray: any[], attr: IAttribute): { name: string; color: string }[] { const uniqueCat = Array.from(new Set(mergedDataArray.map((elem) => elem[attr.dataKey]))); const categoryColors = uniqueCat.map((cat, i) => { - return { name: cat, color: CohortColorSchema.get(i) }; + return { name: cat, color: CoralColorSchema.get(i) }; }); return categoryColors; } diff --git a/src/Taskview/tasks/Filter.ts b/src/Taskview/tasks/Filter.ts index a2655b6..d3e0343 100644 --- a/src/Taskview/tasks/Filter.ts +++ b/src/Taskview/tasks/Filter.ts @@ -1,17 +1,16 @@ - -import {Selection} from 'd3v7'; -import {ICohort} from '../../CohortInterfaces'; -import {IAttribute} from '../../data/Attribute'; -import {getAnimatedLoadingText, log} from '../../util'; -import {AreaChart} from '../visualizations/AreaChart'; -import {AVegaVisualization} from '../visualizations/AVegaVisualization'; -import {Option, OptionGroup, VisConfig} from '../visualizations/config/VisConfig'; -import {DensityPlot} from '../visualizations/DensityPlot'; -import {GroupedBoxplot} from '../visualizations/GroupedBoxplot'; -import {VegaGroupedHistogram} from '../visualizations/GroupedHistogram'; -import {KaplanMeierPlot} from '../visualizations/KaplanMeierPlot'; -import {Scatterplot} from '../visualizations/Scatterplot'; -import {ATask} from './ATask'; +import { Selection } from 'd3v7'; +import { ICohort } from '../../app/interfaces'; +import { IAttribute } from '../../data/IAttribute'; +import { getAnimatedLoadingText, log } from '../../util'; +import { AreaChart } from '../visualizations/AreaChart'; +import { AVegaVisualization } from '../visualizations/AVegaVisualization'; +import { Option, OptionGroup, VisConfig } from '../visualizations/config/VisConfig'; +import { DensityPlot } from '../visualizations/DensityPlot'; +import { GroupedBoxplot } from '../visualizations/GroupedBoxplot'; +import { VegaGroupedHistogram } from '../visualizations/GroupedHistogram'; +import { KaplanMeierPlot } from '../visualizations/KaplanMeierPlot'; +import { Scatterplot } from '../visualizations/Scatterplot'; +import { ATask } from './ATask'; export class Filter extends ATask { public label = `View, Filter & Split`; @@ -161,11 +160,11 @@ export class Filter extends ATask { .classed('selected', (vis) => (vis as any).NAME === (this.vis.constructor as any).NAME) .append('a') .text((vis) => (vis as any).NAME) // cast to any to access static property - .on('click', (event, visClass) => { - if ((visClass as any).NAME !== (this.vis.constructor as any).NAME) { + .on('click', (event, VisClass) => { + if ((VisClass as any).NAME !== (this.vis.constructor as any).NAME) { // check if vis has changed - this.header.selectAll('.vis-selector .vis-type li').classed('selected', (vis) => (vis as any).NAME === (visClass as any).NAME); - this.showWithVis(new visClass()); + this.header.selectAll('.vis-selector .vis-type li').classed('selected', (vis) => (vis as any).NAME === (VisClass as any).NAME); + this.showWithVis(new VisClass()); } }); } diff --git a/src/Taskview/tasks/Prevalence.ts b/src/Taskview/tasks/Prevalence.ts index 2f9a7ad..843a4f4 100644 --- a/src/Taskview/tasks/Prevalence.ts +++ b/src/Taskview/tasks/Prevalence.ts @@ -1,14 +1,13 @@ -import {format, select, transition} from 'd3v7'; +import { format, select, transition } from 'd3v7'; import tippy from 'tippy.js'; -import { Cohort, IBloodlineElement } from '../../Cohort'; -import { ICohort } from '../../CohortInterfaces'; -import { getRootCohort } from '../../cohortview'; -import { colors } from '../../colors'; -import { IAttribute, multiFilter } from '../../data/Attribute'; -import { IEqualsList, INumRange } from '../../rest'; -import { Task } from '../../Tasks'; +import { ICohort, IBloodlineElement } from '../../app/interfaces'; +import { IEqualsList, INumRange } from '../../base/interfaces'; +import { CohortContext } from '../../CohortContext'; +import { colors } from '../../config/colors'; +import { IAttribute, multiFilter } from '../../data'; +import type { Task } from '../../Tasks'; import { createHTMLElementWithClasses, getSessionStorageItem, setSessionStorageItem } from '../../util'; -import { easyLabelFromFilter } from '../../utilLabels'; +import { easyLabelFromFilter } from '../../utils/labels'; import { ATask } from './ATask'; interface ITaskAttributValue { @@ -17,7 +16,7 @@ interface ITaskAttributValue { values: Array; } interface ICohortAndTasksConfig { - cht: Cohort; + cht: ICohort; size: number; refSize: number; attributeValue: ITaskAttributValue[]; @@ -48,7 +47,7 @@ export class Prevalence extends ATask { private prevalencePacks: IPrevalencePack[] = []; - private baseCohort: Cohort; + private baseCohort: ICohort; private baseCohortSize: number; @@ -89,11 +88,11 @@ export class Prevalence extends ATask { const parentTaskId = parentTaskIDs.length === 0 ? null : parentTaskIDs[0]; // get current cohort - let currentCht: Cohort; + let currentCht: ICohort; if (parentTaskId === null) { currentCht = this.baseCohort; } else { - currentCht = cohorts[chtIndex] as Cohort; + currentCht = cohorts[chtIndex] as ICohort; } // create prevalence pack for the current cohort @@ -192,7 +191,7 @@ export class Prevalence extends ATask { await Promise.all(updatePromises); } - private createPrevalenceCohortPack(container: HTMLDivElement, chtIndex: number, parentTaskId: string, cohort: Cohort) { + private createPrevalenceCohortPack(container: HTMLDivElement, chtIndex: number, parentTaskId: string, cohort: ICohort) { // log.debug('cohort pack: ', {container, chtIndex, parentTaskId, cohort}); const divPrevPack = document.createElement('div'); @@ -218,7 +217,7 @@ export class Prevalence extends ATask { } // crates fot each cohort a cohort and its tasks attribute value pair configuration - private createCohortAndTasksConfig(cohort: Cohort, bloodline: IBloodlineElement[], tasks: Task[]): ICohortAndTasksConfig { + private createCohortAndTasksConfig(cohort: ICohort, bloodline: IBloodlineElement[], tasks: Task[]): ICohortAndTasksConfig { const chtSize = cohort.getRetrievedSize(); // const refSize = bloodline[bloodline.length - 1].size; // is the root cohort size const refSize = chtSize; @@ -228,7 +227,7 @@ export class Prevalence extends ATask { // get the index of the current task in the bloodline const currTaskIdx = bloodline.map((bItem) => bItem.obj.id).indexOf(elem.id); // the corresponding cohort to the task is always the element before the task in the bloodline - const currChild = bloodline[currTaskIdx - 1].obj as Cohort; + const currChild = bloodline[currTaskIdx - 1].obj as ICohort; const taskAttValue = { taskId: elem.id, attributes: elem.attributes, @@ -350,7 +349,7 @@ export class Prevalence extends ATask { this.createClickableTasks(d, chtIndex, index, nodes); }); - // ### 3. row: cohort + // ### 3. row: ICohort // row container const divChtCreation = document.createElement('div'); divChtCreation.classList.add('prev-cht-creation', 'prev-row', 'legend-task-row'); @@ -807,6 +806,8 @@ export class Prevalence extends ATask { for (const at of activeTasks) { const attValue = taskpair.filter((elem) => elem.taskId === at.id)[0].values; // create new cohort in db with the attribute and value + // TODO: fix me + // eslint-disable-next-line no-await-in-loop newBaseCohort = await multiFilter(oldBaseCohort, at.attributes, attValue); oldBaseCohort = newBaseCohort; } @@ -817,6 +818,9 @@ export class Prevalence extends ATask { for (const nat of notActiveTasks) { // log.debug('not active Task pair: ', {attribute: nat.attribute, value: valExclMVForTask}); // create new cohort in db with the attribute and value + + // TODO: fix me + // eslint-disable-next-line no-await-in-loop newBaseCohort = await multiFilter(oldBaseCohort, nat.attributes, new Array(nat.attributes.length).fill(valExclMVForTask)); oldBaseCohort = newBaseCohort; } @@ -1017,7 +1021,7 @@ export class Prevalence extends ATask { // sets the base cohort on which all task operations will be applied private setBaseCohort() { - this.baseCohort = getRootCohort(); + this.baseCohort = CohortContext.referenceCohort; this.baseCohortSize = this.baseCohort.getRetrievedSize(); } diff --git a/src/Taskview/visualizations/AVegaVisualization.ts b/src/Taskview/visualizations/AVegaVisualization.ts index cd1de9a..fb0f0c0 100644 --- a/src/Taskview/visualizations/AVegaVisualization.ts +++ b/src/Taskview/visualizations/AVegaVisualization.ts @@ -1,18 +1,19 @@ -import {format, select} from 'd3v7'; -import {cloneDeep} from 'lodash'; +/* eslint-disable @typescript-eslint/no-this-alias */ +import { format, select } from 'd3v7'; +import { cloneDeep } from 'lodash'; import tippy from 'tippy.js'; import { View as VegaView } from 'vega'; import vegaEmbed from 'vega-embed'; import { TopLevelSpec as VegaLiteSpec } from 'vega-lite'; -import { Cohort, getCohortLabel } from '../../Cohort'; -import { ICohort } from '../../CohortInterfaces'; -import { IAttribute, IdValuePair } from '../../data/Attribute'; -import { IEqualsList, INumRange, NumRangeOperators } from '../../rest'; -import { CohortColorSchema, IFilterDesc, log } from '../../util'; -import { FilterEvent, SplitEvent } from '../../utilCustomEvents'; +import { getCohortLabel } from '../../Cohort'; +import { ICohort } from '../../app/interfaces'; +import { IFilterDesc, log } from '../../util'; +import { FilterEvent, SplitEvent } from '../../base/events'; import { Option, VisConfig } from './config/VisConfig'; import { DATA_LABEL } from './constants'; import { IVisualization } from './IVisualization'; +import { IAttribute, IdValuePair } from '../../data/IAttribute'; +import { IEqualsList, INumRange, NumRangeOperators } from '../../base/interfaces'; export const MISSING_VALUES_LABEL = 'Missing Values'; export const FACETED_CHARTS_WIDTH = 520; @@ -50,7 +51,7 @@ export abstract class AVegaVisualization implements IVegaVisualization { protected data; - protected cohorts: Cohort[]; + protected cohorts: ICohort[]; protected vegaLiteSpec; @@ -64,7 +65,7 @@ export abstract class AVegaVisualization implements IVegaVisualization { protected config: VisConfig[] = []; - constructor(protected vegaLiteOptions: Object = {}) {} + constructor(protected vegaLiteOptions: object = {}) {} clearSelection() { if (this.vegaView) { @@ -312,9 +313,9 @@ export abstract class SingleAttributeVisualization extends AVegaVisualization { protected hideVisualization: boolean; - protected nullValueMap: Map>; + protected nullValueMap: Map>; - async show(container: HTMLDivElement, attributes: IAttribute[], cohorts: Cohort[]) { + async show(container: HTMLDivElement, attributes: IAttribute[], cohorts: ICohort[]) { log.debug('show: ', { container, attributes, cohorts }); if (cohorts.length <= 0) { @@ -355,7 +356,7 @@ export abstract class SingleAttributeVisualization extends AVegaVisualization { const flatData = data.flat(1); // check if all values are null - this.nullValueMap = new Map>(); // Map: Attribute -> Cohort --> number of null values per cohort per attribute + this.nullValueMap = new Map>(); // Map: Attribute -> Cohort --> number of null values per cohort per attribute this.nullValueMap.set(this.attribute.dataKey, new Map(this.cohorts.map((cht) => [cht, 0]))); // init map with 0 for all attribues let nullValues = 0; @@ -472,60 +473,58 @@ export abstract class SingleAttributeVisualization extends AVegaVisualization { }, ], }); - } else { + } else if (this.attribute.type === 'number') { // 1 cohort, multiple categories, or one category, multiple cohorts - if (this.attribute.type === 'number') { - // n cohorts, one range (can't be more because we use one interval selection) - const chtRanges: { cht: ICohort; ranges: { from: number; to: number }[] }[] = []; // create a list of chts and their filtered categories - for (const bin of bins) { - const chtRange = chtRanges.find((elem) => elem.cht.id === bin.cohort.id); - if (chtRange !== undefined) { - // I handled this cohort before - chtRange.ranges.push({ from: bin.from as number, to: bin.to as number }); // add range to exisiting list - } else { - // new cht, create object and init range array - chtRanges.push({ cht: bin.cohort, ranges: [{ from: bin.from as number, to: bin.to as number }] }); - } + // n cohorts, one range (can't be more because we use one interval selection) + const chtRanges: { cht: ICohort; ranges: { from: number; to: number }[] }[] = []; // create a list of chts and their filtered categories + for (const bin of bins) { + const chtRange = chtRanges.find((elem) => elem.cht.id === bin.cohort.id); + if (chtRange !== undefined) { + // I handled this cohort before + chtRange.ranges.push({ from: bin.from as number, to: bin.to as number }); // add range to exisiting list + } else { + // new cht, create object and init range array + chtRanges.push({ cht: bin.cohort, ranges: [{ from: bin.from as number, to: bin.to as number }] }); } - // get a filter for the categories per cohort - filterDesc = chtRanges.map((elem) => { - const filters = []; - for (const rg of elem.ranges) { - filters.push(this.getNumericalFilterAllInclusive(rg.from as number, rg.to as number)); - } - return { - cohort: elem.cht, - filter: [ - { - attr: this.attribute, - range: filters, - }, - ], - }; - }); - } else { - const chtCats: { cht: ICohort; cats: string[] }[] = []; // create a list of chts and their filtered categories - for (const bin of bins) { - const chtCat = chtCats.find((elem) => elem.cht.id === bin.cohort.id); - if (chtCat !== undefined) { - // I handled this cohort before - chtCat.cats.push(String(bin.from)); // add category to exisiting list - } else { - // new cht, create object and init category array - chtCats.push({ cht: bin.cohort, cats: [String(bin.from)] }); - } + } + // get a filter for the categories per cohort + filterDesc = chtRanges.map((elem) => { + const filters = []; + for (const rg of elem.ranges) { + filters.push(this.getNumericalFilterAllInclusive(rg.from as number, rg.to as number)); } - // get a filter for the categories per cohort - filterDesc = chtCats.map((elem) => ({ + return { cohort: elem.cht, filter: [ { attr: this.attribute, - range: this.getCategoricalFilter(elem.cats), + range: filters, }, ], - })); + }; + }); + } else { + const chtCats: { cht: ICohort; cats: string[] }[] = []; // create a list of chts and their filtered categories + for (const bin of bins) { + const chtCat = chtCats.find((elem) => elem.cht.id === bin.cohort.id); + if (chtCat !== undefined) { + // I handled this cohort before + chtCat.cats.push(String(bin.from)); // add category to exisiting list + } else { + // new cht, create object and init category array + chtCats.push({ cht: bin.cohort, cats: [String(bin.from)] }); + } } + // get a filter for the categories per cohort + filterDesc = chtCats.map((elem) => ({ + cohort: elem.cht, + filter: [ + { + attr: this.attribute, + range: this.getCategoricalFilter(elem.cats), + }, + ], + })); } log.debug('show filter description: ', filterDesc); this.container.dispatchEvent(new FilterEvent(filterDesc)); @@ -825,11 +824,11 @@ export abstract class SingleAttributeVisualization extends AVegaVisualization { const scale = this.vegaView.scale('x'); // if one or both ranges are set, replace with values - if (range[0] !== undefined && !isNaN(range[0])) { + if (range[0] !== undefined && !Number.isNaN(range[0])) { scaledRange[0] = scale(range[0]); // get min value from input } - if (range[1] !== undefined && !isNaN(range[1])) { + if (range[1] !== undefined && !Number.isNaN(range[1])) { scaledRange[1] = scale(range[1]); // get max value from input if (range[0] === range[1]) { scaledRange[1] = scale(range[1]) + 10 ** -10; // the 10^(-10) are independent of the attribute domain (i.e. values of 0 to 1 or in millions) because we add it after scaling (its a fraction of a pixel) diff --git a/src/Taskview/visualizations/AreaChart.ts b/src/Taskview/visualizations/AreaChart.ts index d6f8224..7b71dc0 100644 --- a/src/Taskview/visualizations/AreaChart.ts +++ b/src/Taskview/visualizations/AreaChart.ts @@ -1,15 +1,15 @@ import log from 'loglevel'; import { TopLevelSpec as VegaLiteSpec } from 'vega-lite'; import { getCohortLabels } from '../../Cohort'; -import { ICohort } from '../../CohortInterfaces'; -import { IdValuePair } from '../../data/Attribute'; +import { ICohort } from '../../app/interfaces'; import { DATA_LABEL } from './constants'; import { MultiAttributeVisualization } from './MultiAttributeVisualization'; +import { IdValuePair } from '../../data/IAttribute'; export class AreaChart extends MultiAttributeVisualization { static readonly NAME = 'Area Chart'; - constructor(vegaLiteOptions: Object = {}) { + constructor(vegaLiteOptions: object = {}) { super(vegaLiteOptions); } diff --git a/src/Taskview/visualizations/DensityPlot.ts b/src/Taskview/visualizations/DensityPlot.ts index 6577b4f..b7bfccb 100644 --- a/src/Taskview/visualizations/DensityPlot.ts +++ b/src/Taskview/visualizations/DensityPlot.ts @@ -1,12 +1,12 @@ -import {format, select} from 'd3v7'; +import { format, select } from 'd3v7'; import log from 'loglevel'; import { Spec as VegaSpec } from 'vega'; import { TopLevelSpec as VegaLiteSpec } from 'vega-lite'; -import { ICohort } from '../../CohortInterfaces'; -import { IdValuePair } from '../../data/Attribute'; +import { ICohort } from '../../app/interfaces'; import { AVegaVisualization, SingleAttributeVisualization } from './AVegaVisualization'; import { DATA_LABEL } from './constants'; import { countConfig, counts } from './config/CountCounfig'; +import { IdValuePair } from '../../data/IAttribute'; export class DensityPlot extends SingleAttributeVisualization { static readonly NAME = 'Density Plot'; @@ -15,7 +15,7 @@ export class DensityPlot extends SingleAttributeVisualization { protected readonly type = 'quantitative'; - constructor(vegaLiteOptions: Object = {}) { + constructor(vegaLiteOptions: object = {}) { super(vegaLiteOptions); this.config = [{ icon: '', label: 'Density Estimation Method', groups: [countConfig] }]; @@ -383,11 +383,11 @@ export class DensityPlot extends SingleAttributeVisualization { update: { cursor: { value: 'text' }, tooltip: { - signal: `{\'${this.attribute.label}\': format(datum[\'value\'], \'\'), \'Density\': format(datum[\'density\'], \'\'), \'value\': format(datum[\'value\'], \'\'), \'${DATA_LABEL}\': isValid(datum[\'${DATA_LABEL}\']) ? datum[\'${DATA_LABEL}\'] : \'\'+datum[\'${DATA_LABEL}\']}`, + signal: `{'${this.attribute.label}': format(datum['value'], ''), 'Density': format(datum['density'], ''), 'value': format(datum['value'], ''), '${DATA_LABEL}': isValid(datum['${DATA_LABEL}']) ? datum['${DATA_LABEL}'] : ''+datum['${DATA_LABEL}']}`, }, stroke: { scale: 'color', field: DATA_LABEL }, description: { - signal: `\'${this.attribute.label}: \' + (format(datum[\'value\'], \'\')) + \'; Density: \' + (format(datum[\'density\'], \'\')) + \'; value: \' + (format(datum[\'value\'], \'\')) + \'; ${DATA_LABEL}: \' + (isValid(datum[\'${DATA_LABEL}\']) ? datum[\'${DATA_LABEL}\'] : \'\'+datum[\'${DATA_LABEL}\'])`, + signal: `'${this.attribute.label}: ' + (format(datum['value'], '')) + '; Density: ' + (format(datum['density'], '')) + '; value: ' + (format(datum['value'], '')) + '; ${DATA_LABEL}: ' + (isValid(datum['${DATA_LABEL}']) ? datum['${DATA_LABEL}'] : ''+datum['${DATA_LABEL}'])`, }, x: { scale: 'x', field: 'value' }, y: { scale: 'y', field: 'density' }, diff --git a/src/Taskview/visualizations/GroupedBoxplot.ts b/src/Taskview/visualizations/GroupedBoxplot.ts index 6fb6c8e..44de9a6 100644 --- a/src/Taskview/visualizations/GroupedBoxplot.ts +++ b/src/Taskview/visualizations/GroupedBoxplot.ts @@ -1,16 +1,17 @@ -import {format, select} from 'd3v7'; +/* eslint-disable @typescript-eslint/no-this-alias */ +import { format, select } from 'd3v7'; import log from 'loglevel'; import { Spec as VegaSpec } from 'vega'; import { TopLevelSpec as VegaLiteSpec } from 'vega-lite'; -import { ICohort } from '../../CohortInterfaces'; -import { IAttribute, IdValuePair } from '../../data/Attribute'; -import { NumRangeOperators } from '../../rest'; +import { ICohort } from '../../app/interfaces'; import { IAttributeFilter, IFilterDesc } from '../../util'; -import { FilterEvent, SplitEvent } from '../../utilCustomEvents'; +import { FilterEvent, SplitEvent } from '../../base/events'; import { AVegaVisualization } from './AVegaVisualization'; import { groupByConfig } from './config/GroupConfig'; import { BRUSH_DATA_END, BRUSH_DATA_NAME, BRUSH_DATA_START, DATA_LABEL } from './constants'; import { MultiAttributeVisualization } from './MultiAttributeVisualization'; +import { NumRangeOperators } from '../../base'; +import { IAttribute, IdValuePair } from '../../data'; export class GroupedBoxplot extends MultiAttributeVisualization { static readonly NAME = 'Boxplot'; @@ -21,7 +22,7 @@ export class GroupedBoxplot extends MultiAttributeVisualization { brushData: object[] = []; - constructor(vegaLiteOptions: Object = {}) { + constructor(vegaLiteOptions: object = {}) { super(vegaLiteOptions); this.config = [{ icon: '', label: 'Group', groups: [groupByConfig] }]; @@ -67,10 +68,10 @@ export class GroupedBoxplot extends MultiAttributeVisualization { const newRange = scale.domain(); // if one or both ranges are set, replace with values - if (range[0] !== undefined && !isNaN(range[0])) { + if (range[0] !== undefined && !Number.isNaN(range[0])) { newRange[0] = range[0]; // get min value from input } - if (range[1] !== undefined && !isNaN(range[1])) { + if (range[1] !== undefined && !Number.isNaN(range[1])) { newRange[1] = range[1]; // get max value from input if (range[0] === range[1]) { newRange[1] = scale.invert(scale(range[1]) + 10 ** -10); // the 10^(-10) are independent of the attribute domain (i.e. values of 0 to 1 or in millions) because we add it after scaling (its a fraction of a pixel) diff --git a/src/Taskview/visualizations/GroupedHistogram.ts b/src/Taskview/visualizations/GroupedHistogram.ts index 6bdfec8..b32e079 100644 --- a/src/Taskview/visualizations/GroupedHistogram.ts +++ b/src/Taskview/visualizations/GroupedHistogram.ts @@ -2,9 +2,8 @@ import { TopLevelSpec as VegaLiteSpec } from 'vega-lite'; import { Field } from 'vega-lite/build/src/channeldef'; import { TopLevelUnitSpec } from 'vega-lite/build/src/spec/unit'; import { getCohortLabel } from '../../Cohort'; -import { ICohort } from '../../CohortInterfaces'; -import { colors } from '../../colors'; -import { IdValuePair } from '../../data/Attribute'; +import { ICohort } from '../../app/interfaces'; +import { colors } from '../../config/colors'; import { log } from '../../util'; import { AVegaVisualization, FACETED_CHARTS_WIDTH } from './AVegaVisualization'; import { groupByConfig } from './config/GroupConfig'; @@ -12,13 +11,14 @@ import { dataConfig } from './config/ScaleConfig'; import { sortByConfig, sortOrderConfig } from './config/SortConfig'; import { DATA_LABEL } from './constants'; import { VegaHistogram } from './Histogram'; +import { IdValuePair } from '../../data/IAttribute'; export class VegaGroupedHistogram extends VegaHistogram { static readonly COUNT = 'Count'; protected readonly type = 'nominal'; - constructor(vegaLiteOptions: Object = {}) { + constructor(vegaLiteOptions: object = {}) { super(vegaLiteOptions); this.config = [ diff --git a/src/Taskview/visualizations/Histogram.ts b/src/Taskview/visualizations/Histogram.ts index df22def..a9fc51d 100644 --- a/src/Taskview/visualizations/Histogram.ts +++ b/src/Taskview/visualizations/Histogram.ts @@ -1,7 +1,7 @@ import { TopLevelSpec as VegaLiteSpec } from 'vega-lite'; -import { ICohort } from '../../CohortInterfaces'; -import { IdValuePair } from '../../data/Attribute'; -import { colors } from '../../colors'; +import { ICohort } from '../../app/interfaces'; +import { colors } from '../../config/colors'; +import { IdValuePair } from '../../data/IAttribute'; import { log } from '../../util'; import { AVegaVisualization, SingleAttributeVisualization } from './AVegaVisualization'; import { DATA_LABEL } from './constants'; diff --git a/src/Taskview/visualizations/IVisualization.ts b/src/Taskview/visualizations/IVisualization.ts index 0394c51..33943b1 100644 --- a/src/Taskview/visualizations/IVisualization.ts +++ b/src/Taskview/visualizations/IVisualization.ts @@ -1,5 +1,5 @@ -import { ICohort } from '../../CohortInterfaces'; -import { IAttribute } from '../../data/Attribute'; +import type { ICohort } from '../../app/interfaces'; +import type { IAttribute } from '../../data/IAttribute'; export interface IVisualization { destroy(); diff --git a/src/Taskview/visualizations/KaplanMeierPlot.ts b/src/Taskview/visualizations/KaplanMeierPlot.ts index e10edf3..d65b5eb 100644 --- a/src/Taskview/visualizations/KaplanMeierPlot.ts +++ b/src/Taskview/visualizations/KaplanMeierPlot.ts @@ -1,16 +1,16 @@ import log from 'loglevel'; -import {select} from 'd3v7'; -import {TopLevelSpec as VegaLiteSpec} from 'vega-lite'; -import {Spec as VegaSpec, None} from 'vega'; -import {IdValuePair, ServerColumnAttribute} from '../../data/Attribute'; -import {DATA_LABEL} from './constants'; -import {desc, op, from, rolling, table, not} from 'arquero'; -import {getCohortLabel, getCohortLabels} from '../../Cohort'; -import {SingleAttributeVisualization, AVegaVisualization} from './AVegaVisualization'; -import {ICohort} from '../../CohortInterfaces'; -import {OrderKeys, ExprList} from 'arquero/dist/types/table/transformable'; -import {confidenceToggleGroup, confidenceNone} from './config/ConfidenceConfig'; +import { TopLevelSpec as VegaLiteSpec } from 'vega-lite'; +import { Spec as VegaSpec, None } from 'vega'; +import { desc, op, from, rolling, table, not } from 'arquero'; +import { OrderKeys, ExprList } from 'arquero/dist/types/table/transformable'; +import { ServerColumnAttribute } from '../../data/Attribute'; +import { DATA_LABEL } from './constants'; +import { getCohortLabel, getCohortLabels } from '../../Cohort'; +import { SingleAttributeVisualization, AVegaVisualization } from './AVegaVisualization'; +import { ICohort } from '../../app/interfaces'; +import { confidenceToggleGroup, confidenceNone } from './config/ConfidenceConfig'; import confidenceIcon from '../../assets/icons/confidence.svg'; +import { IdValuePair } from '../../data/IAttribute'; export class KaplanMeierPlot extends SingleAttributeVisualization { static readonly NAME = 'Kaplan-Meier Plot'; @@ -24,7 +24,7 @@ export class KaplanMeierPlot extends SingleAttributeVisualization { protected readonly type = 'quantitative'; - constructor(vegaLiteOptions: Object = {}) { + constructor(vegaLiteOptions: object = {}) { super(vegaLiteOptions); this.config = [ @@ -56,6 +56,8 @@ export class KaplanMeierPlot extends SingleAttributeVisualization { } const dataPromises = this.cohorts.map((cht) => { + // TODO: fix me + // eslint-disable-next-line no-async-promise-executor const promise = new Promise(async (resolve, reject) => { const chtDataPromises = attributes.map((attr) => attr.getData(cht.dbId)); try { diff --git a/src/Taskview/visualizations/MultiAttributeVisualization.ts b/src/Taskview/visualizations/MultiAttributeVisualization.ts index 1053591..4277ef9 100644 --- a/src/Taskview/visualizations/MultiAttributeVisualization.ts +++ b/src/Taskview/visualizations/MultiAttributeVisualization.ts @@ -1,11 +1,12 @@ +/* eslint-disable @typescript-eslint/no-this-alias */ import * as aq from 'arquero'; -import {format, select} from 'd3v7'; +import { format, select } from 'd3v7'; import tippy from 'tippy.js'; import vegaEmbed from 'vega-embed'; import { TopLevelSpec as VegaLiteSpec } from 'vega-lite'; -import { Cohort, getCohortLabel } from '../../Cohort'; -import { ICohort } from '../../CohortInterfaces'; -import { IAttribute, IdValuePair } from '../../data/Attribute'; +import { getCohortLabel } from '../../Cohort'; +import { ICohort } from '../../app/interfaces'; +import { IAttribute, IdValuePair } from '../../data'; import { log, selectLast } from '../../util'; import { AVegaVisualization } from './AVegaVisualization'; import { DATA_LABEL } from './constants'; @@ -23,9 +24,9 @@ export abstract class MultiAttributeVisualization extends AVegaVisualization { protected colorPalette: string[]; - protected nullValueMap: Map>; + protected nullValueMap: Map>; - async show(container: HTMLDivElement, attributes: IAttribute[], cohorts: Cohort[]) { + async show(container: HTMLDivElement, attributes: IAttribute[], cohorts: ICohort[]) { log.debug('show: ', { container, attributes, cohorts }); if (attributes.length <= 1) { throw new Error('Number of attributes must be at least 2'); @@ -36,6 +37,8 @@ export abstract class MultiAttributeVisualization extends AVegaVisualization { this.attributes = attributes; // Create an array, with on entry per cohort, which contains an array with one entry per attribute, i.e. for 2 cohorts and 2 attributes (A1,A2) we get [[A1, A2], [A1, A2]] const dataPromises = cohorts.map((cht, chtIndex) => { + // TODO: fix me + // eslint-disable-next-line no-async-promise-executor const promise = new Promise(async (resolve, reject) => { const chtDataPromises = this.attributes.map((attr) => attr.getData(cht.dbId)); try { @@ -76,7 +79,7 @@ export abstract class MultiAttributeVisualization extends AVegaVisualization { const flatData = data.flat(1); // check if all values are null - this.nullValueMap = new Map>(); // Map: Attribute -> Cohort --> number of null values per cohort per attribute + this.nullValueMap = new Map>(); // Map: Attribute -> Cohort --> number of null values per cohort per attribute this.attributes.forEach((attr) => this.nullValueMap.set(attr.dataKey, new Map(this.cohorts.map((cht) => [cht, 0])))); // init map with 0 for all attribues let nullValues = 0; @@ -339,10 +342,10 @@ export abstract class MultiAttributeVisualization extends AVegaVisualization { const scale = this.vegaView.scale(axis); // if one or both ranges are set, replace with values - if (range[0] !== undefined && !isNaN(range[0])) { + if (range[0] !== undefined && !Number.isNaN(range[0])) { scaledRange[0] = scale(range[0]); // get min value from input } - if (range[1] !== undefined && !isNaN(range[1])) { + if (range[1] !== undefined && !Number.isNaN(range[1])) { scaledRange[1] = scale(range[1]); // get max value from input if (range[0] === range[1]) { scaledRange[1] = scale(range[1]) + 10 ** -10; // the 10^(-10) are independent of the attribute domain (i.e. values of 0 to 1 or in millions) because we add it after scaling (its a fraction of a pixel) @@ -363,11 +366,11 @@ export abstract class MultiAttributeVisualization extends AVegaVisualization { parseFloat((select(this.controls).select(`input.maximum[data-axis="${axis}"]`).node() as HTMLInputElement).value), ]; - if (range.some((rangeNum) => rangeNum === undefined || isNaN(rangeNum))) { + if (range.some((rangeNum) => rangeNum === undefined || Number.isNaN(rangeNum))) { const domain = this.vegaView.scale(axis).domain(); for (const i in range) { - if (range[i] === undefined || isNaN(range[i])) { + if (range[i] === undefined || Number.isNaN(range[i])) { range[i] = domain[i]; } } diff --git a/src/Taskview/visualizations/Scatterplot.ts b/src/Taskview/visualizations/Scatterplot.ts index 7f74f7d..be07334 100644 --- a/src/Taskview/visualizations/Scatterplot.ts +++ b/src/Taskview/visualizations/Scatterplot.ts @@ -1,23 +1,25 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable global-require */ import * as Comlink from 'comlink'; -import {select} from 'd3v7'; -import {Spec as VegaSpec} from 'vega'; -import {TopLevelSpec as VegaLiteSpec} from 'vega-lite'; -import {Cohort} from '../../Cohort'; -import {AttributeType, IAttribute, IdValuePair, ServerColumnAttribute} from '../../data/Attribute'; -import {NumRangeOperators} from '../../rest'; -import {IFilterDesc, inRange} from '../../util'; -import {FilterEvent} from '../../utilCustomEvents'; -import {DATA_LABEL} from './constants'; -import {AxisType, MultiAttributeVisualization} from './MultiAttributeVisualization'; -import {TopLevel, LayerSpec} from 'vega-lite/build/src/spec'; -import {Field} from 'vega-lite/build/src/channeldef'; +import { select } from 'd3v7'; +import { Spec as VegaSpec } from 'vega'; +import { TopLevelSpec as VegaLiteSpec } from 'vega-lite'; +import { TopLevel, LayerSpec } from 'vega-lite/build/src/spec'; +import { Field } from 'vega-lite/build/src/channeldef'; +import { ICohort } from '../../app/interfaces'; +import { AttributeType, IAttribute, IdValuePair, ServerColumnAttribute } from '../../data'; +import { NumRangeOperators } from '../../base'; +import { IFilterDesc, inRange } from '../../util'; +import { FilterEvent } from '../../base/events'; +import { DATA_LABEL } from './constants'; +import { AxisType, MultiAttributeVisualization } from './MultiAttributeVisualization'; export class Scatterplot extends MultiAttributeVisualization { static readonly NAME: string = 'Scatterplot'; protected checkAttributeType = false; - constructor(vegaLiteOptions: Object = {}) { + constructor(vegaLiteOptions: object = {}) { super(vegaLiteOptions); } @@ -1042,7 +1044,7 @@ export class TsneScatterplot extends Scatterplot { originalAttributes: IAttribute[]; - constructor(vegaLiteOptions: Object = {}) { + constructor(vegaLiteOptions: object = {}) { super(vegaLiteOptions); this.checkAttributeType = false; } @@ -1058,7 +1060,7 @@ export class TsneScatterplot extends Scatterplot { return scatterSpec; } - async show(container: HTMLDivElement, attributes: IAttribute[], cohorts: Cohort[]) { + async show(container: HTMLDivElement, attributes: IAttribute[], cohorts: ICohort[]) { super.show(container, attributes, cohorts); } @@ -1066,8 +1068,8 @@ export class TsneScatterplot extends Scatterplot { this.addProgressBar(); const oneHotWorker = new (require('worker-loader?name=OneHotEncoder.js!./dimreduce/OneHotEncoder.worker'))(); - const oneHotClass = Comlink.wrap(oneHotWorker) as any; - const oneHot = await new oneHotClass(); + const OneHotClass = Comlink.wrap(oneHotWorker) as any; + const oneHot = await new OneHotClass(); // Note: numerical attributes will be normalized const oneHotData = await oneHot.encode(data, this.attributes); oneHot[Comlink.releaseProxy](); @@ -1080,6 +1082,7 @@ export class TsneScatterplot extends Scatterplot { const tsneWorker = new (require('worker-loader?name=tsne.worker.js!./dimreduce/tsne.worker'))(); this.tsneClass = Comlink.wrap(tsneWorker) as any; + // eslint-disable-next-line new-cap this.tsne = await new this.tsneClass(opt); this.tsne.initDataRaw(oneHotData); diff --git a/src/Taskview/visualizations/dimreduce/OneHotEncoder.ts b/src/Taskview/visualizations/dimreduce/OneHotEncoder.ts index 92f38d3..3d85b3c 100644 --- a/src/Taskview/visualizations/dimreduce/OneHotEncoder.ts +++ b/src/Taskview/visualizations/dimreduce/OneHotEncoder.ts @@ -12,7 +12,7 @@ export class OneHotEncoder { encode(data: Array, attributes: Array) { const hotData = []; - if (data?.length ?? 0 > 0) { + if (data?.length > 0) { // gather categories of the categorical attributes for (const attr of attributes) { for (const item of data) { diff --git a/src/Tooltip.ts b/src/Tooltip.ts deleted file mode 100644 index 3604296..0000000 --- a/src/Tooltip.ts +++ /dev/null @@ -1,64 +0,0 @@ -import tippy from 'tippy.js'; -import { taskview } from './cohortview'; -import { toAttribute } from './data/Attribute'; -import { SearchBar } from './Taskview/SearchBar'; - -export function createSearchBarTooltip(elemWithTooltip: HTMLDivElement, cssClassName: string, database: string, view: string, positionStart = true) { - // start of tooltip content - const divAddAttr = document.createElement('div'); - divAddAttr.classList.add('tooltip-serachbar'); - const divText = document.createElement('div'); - divText.innerHTML = 'Add attribute columns to the input and output sides:'; - divText.classList.add('tooltip-txt'); - divAddAttr.appendChild(divText); - const divSearchBar = document.createElement('div'); - const searchBar = new SearchBar(divSearchBar, database, view, cssClassName); - divAddAttr.appendChild(divSearchBar); - - const divControls = document.createElement('div'); - const divOK = document.createElement('div'); - divOK.classList.add('okay', 'btn', 'btn-coral', 'tooltip-btn'); - divOK.innerHTML = 'Okay'; - divOK.addEventListener('click', () => { - // get options from search bar - const options = searchBar ? searchBar.getSelectedOptions() : []; - // convert options to attributes - const attributes = options.map((opt) => toAttribute(opt, database, view)); - // add attributes to taskview - taskview.addMultipleAttributeColumns(attributes, true, true); - // remove options and close tooltip - elemWithTooltip.click(); - }); - - divControls.classList.add('tooltip-controls'); - const divCancel = document.createElement('div'); - divCancel.classList.add('cancel', 'btn', 'btn-coral', 'tooltip-btn'); - divCancel.innerHTML = 'Cancel'; - divCancel.addEventListener('click', () => { - // remove options and close tooltip - elemWithTooltip.click(); - }); - - divControls.appendChild(divOK); - divControls.appendChild(divCancel); - divAddAttr.appendChild(divControls); - - elemWithTooltip.addEventListener('click', () => { - searchBar.removeAllSelectedOptions(); // remove all selected options form the search bar - elemWithTooltip.classList.toggle('active'); - }); - - // add the tippy tool tip - tippy(elemWithTooltip, { - content: divAddAttr, - allowHTML: true, - interactive: true, // tooltip is interactive: clickable/hoverable content - placement: positionStart ? 'top-start' : 'top-end', - appendTo: () => document.body, // add the content to the document as a child - trigger: 'click', // element has to be clicked to show the tooltip - hideOnClick: 'toggle', // the tooltip is closed when the element is clicked again - arrow: true, // show tooltip arrow - zIndex: 9000, // default z-index: 9999 (but the searchbar option container has z-index of 9001) - maxWidth: 'none', // default max. width is 350px - }); -} diff --git a/src/app/Coral.ts b/src/app/Coral.ts new file mode 100644 index 0000000..93c9725 --- /dev/null +++ b/src/app/Coral.ts @@ -0,0 +1,54 @@ +import { select } from 'd3v7'; +import { ATDPApplication, CLUEGraphManager, ITDPOptions, ProvenanceGraph } from 'tdp_core'; +import { IClientConfig } from 'visyn_core/base'; +import { CoralApp, ICoralClientConfig } from './CoralApp'; +import { log } from '../util'; + +/** + * The app for this website, embeds our Cohort App + */ +export class Coral extends ATDPApplication { + constructor(name: string, loginDialog: string, showCookieDisclaimer = true) { + super({ + prefix: 'coral', + name, + loginForm: loginDialog, + /** + * Link to help and show help in `Coral at a Glance` page instead + */ + showHelpLink: `${`${window.location.href.split('app/')[0]}#/help`}`, + showCookieDisclaimer, + /** + * Show content in the `Coral at a Glance` page instead + */ + showAboutLink: false, + /** + * Show content in the `Coral at a Glance` page instead + */ + showReportBugLink: false, + clientConfig: { + contact: { + href: 'https://github.com/Caleydo/Coral/issues/', + label: 'report an issue', + }, + } as unknown as IClientConfig, + }); + } + + protected createApp(graph: ProvenanceGraph, manager: CLUEGraphManager, main: HTMLElement): CoralApp | PromiseLike { + log.debug('Create App'); + this.replaceHelpIcon(); + return new CoralApp(graph, manager, main, this.options).init(); + } + + private replaceHelpIcon() { + const helpButton = select(this.header.rightMenu).select('li[data-header="helpLink"]'); + helpButton.select('span.fa-stack').remove(); + helpButton.select('a.nav-link').insert('i', ':first-child').attr('class', 'fa fa-question-circle'); + } + + protected initSessionImpl(app: CoralApp) { + log.debug('initSessionImpl. Is Graph empty?', app.graph.isEmpty); + this.jumpToStoredOrLastState(); + } +} diff --git a/src/app.ts b/src/app/CoralApp.ts similarity index 74% rename from src/app.ts rename to src/app/CoralApp.ts index 13ee8a6..ef51b02 100644 --- a/src/app.ts +++ b/src/app/CoralApp.ts @@ -1,41 +1,40 @@ import { select, Selection } from 'd3v7'; import SplitGrid from 'split-grid'; -import { - AppContext, - ATDPApplication, - CLUEGraphManager, - IDatabaseViewDesc, - IObjectRef, - IServerColumn, - ITDPOptions, - NotificationHandler, - ObjectRefUtils, - ProvenanceGraph, - RestBaseUtils, -} from 'tdp_core'; +import { IServerColumn, AppContext } from 'visyn_core/base'; +import { CLUEGraphManager, IDatabaseViewDesc, IObjectRef, ITDPOptions, NotificationHandler, ObjectRefUtils, ProvenanceGraph, RestBaseUtils } from 'tdp_core'; import { cellline, tissue } from 'tdp_publicdb'; import { Instance as TippyInstance } from 'tippy.js'; -import { Cohort, createCohort, createCohortFromDB } from './Cohort'; -import { IElementProvJSON, IElementProvJSONCohort, ITaskParams } from './CohortInterfaces'; -import { cohortOverview, createCohortOverview, destroyOld, loadViewDescription, taskview } from './cohortview'; -import { PanelScoreAttribute } from './data/Attribute'; -import { OnboardingManager } from './OnboardingManager'; -import { CohortOverview } from './Overview'; -import { setDatasetAction } from './Provenance/General'; -import { getDBCohortData } from './rest'; -import { Task } from './Tasks'; -import Taskview, { InputCohort } from './Taskview/Taskview'; -import deleteModal from './templates/DeleteModal.html'; -import welcomeHtml from './templates/Welcome.html'; // webpack imports html to variable -import { getAnimatedLoadingText, handleDataLoadError, log, removeFromArray } from './util'; -import { CohortSelectionEvent, COHORT_SELECTION_EVENT_TYPE, ConfirmTaskEvent, CONFIRM_TASK_EVENT_TYPE, PreviewConfirmEvent } from './utilCustomEvents'; -import { idCellline, idCovid19, idStudent, idTissue, IEntitySourceConfig } from './utilIdTypes'; -import { niceName } from './utilLabels'; +import { createCohort, createCohortFromDB } from '../Cohort'; +import type { IElementProvJSON, IElementProvJSONCohort, ITaskParams, ICohort, IDatasetDesc, IPanelDesc } from './interfaces'; +import { createCohortOverview, destroyOld, loadViewDescription } from '../cohortview'; +import { PanelScoreAttribute } from '../data/Attribute'; +import { OnboardingManager } from '../OnboardingManager'; +import { CohortOverview } from '../Overview'; +import { setDatasetAction } from '../Provenance/General'; +import { getDBCohortData } from '../base/rest'; +import { Task } from '../Tasks'; +import Taskview from '../Taskview/Taskview'; +import deleteModal from '../templates/DeleteModal.html'; +import welcomeHtml from '../templates/Welcome.html'; +import { getAnimatedLoadingText, handleDataLoadError, log } from '../util'; +import { CohortSelectionEvent, ConfirmTaskEvent, CONFIRM_TASK_EVENT_TYPE, PreviewConfirmEvent } from '../base/events'; +import { idCellline, idCovid19, idStudent, idTissue, IEntitySourceConfig } from '../config/entities'; +import { niceName } from '../utils/labels'; +import { CohortSelectionListener } from './CoralSelectionListener'; +import { CohortContext } from '../CohortContext'; + +export interface ICoralClientConfig extends Pick { + contact?: { + href: string; + label: string; + }; +} /** * The Cohort app that does the acutal stuff. */ -export class CohortApp { + +export class CoralApp { private readonly $node: Selection; private $overview: HTMLDivElement; @@ -52,7 +51,7 @@ export class CohortApp { private _taskview: Taskview = null; - private rootCohort: Cohort = null; + private rootCohort: ICohort = null; private datasetEventID = 0; @@ -62,15 +61,15 @@ export class CohortApp { /** * IObjectRef to this CohortApp instance - * @type {IObjectRef} + * @type {IObjectRef} */ - readonly ref: IObjectRef; + readonly ref: IObjectRef; constructor( public readonly graph: ProvenanceGraph, public readonly graphManager: CLUEGraphManager, parent: HTMLElement, - public readonly options: ITDPOptions, + public readonly options: ITDPOptions & { clientConfig: ICoralClientConfig }, ) { this.name = options.name; this.$node = select(parent).append('div').classed('cohort_app', true); @@ -101,21 +100,21 @@ export class CohortApp { for (const task of taskParams) { for (const cht of task.outputCohorts) { log.debug('app sets counter to', 1 + this.chtCounter); - (cht as Cohort).setLabels(`#${this.chtCounter++} ${(cht as Cohort).labelOne}`, (cht as Cohort).labelTwo); + cht.setLabels(`#${this.chtCounter++} ${cht.labelOne}`, cht.labelTwo); } } // confirm the current preview as the result of the task this.$node.node().dispatchEvent(new PreviewConfirmEvent(taskParams, taskAttributes)); // get the new added task (the ones confirmed from the preview) - const tasks: Task[] = cohortOverview.getLastAddedTasks(); - taskview.clearOutput(); // clear taskview output + const tasks: Task[] = CohortContext.cohortOverview.getLastAddedTasks(); + CohortContext.taskview.clearOutput(); // clear taskview output // set output as new input let replace = true; for (const task of tasks) { for (const cht of task.children) { - this.$node.node().dispatchEvent(new CohortSelectionEvent(cht as Cohort, replace)); + this.$node.node().dispatchEvent(new CohortSelectionEvent(cht as ICohort, replace)); replace = false; // replace old selection with first cohort, then add the others if (this.firstOutput) { @@ -244,6 +243,8 @@ export class CohortApp { dropdown.append('li').attr('role', 'separator').classed('dropdown-divider', true); dropdown.append('li').classed('dropdown-header', true).text('Predefined Sets'); + // TODO: check if this can be removed in the future + // eslint-disable-next-line @typescript-eslint/no-this-alias const that = this; dropdown .selectAll('li.data-panel') @@ -258,8 +259,8 @@ export class CohortApp { .on('click', async function (event, d) { // click subset // don't toggle data by checkging what is selected in dropdown - const dataSourcesAndPanels = select(this.parentNode.parentNode).datum() as { source: IEntitySourceConfig; panels: IPanelDesc[] }; // a -> parent = li -> parent = dropdown = ul - const newDataset = { source: dataSourcesAndPanels.source, panel: d, rootCohort: null, chtOverviewElements: null }; + const currDataSourcesAndPanels = select(this.parentNode.parentNode).datum() as { source: IEntitySourceConfig; panels: IPanelDesc[] }; // a -> parent = li -> parent = dropdown = ul + const newDataset = { source: currDataSourcesAndPanels.source, panel: d, rootCohort: null, chtOverviewElements: null }; that.handleDatasetClick.bind(that)(newDataset); }); @@ -348,7 +349,7 @@ export class CohortApp { log.debug('retrievedViewDesctiprion', viewDescription); const idColumn: IServerColumn = viewDescription.columns.find((col) => col.label === 'id') || { column: 'id', label: 'id', type: 'string' }; // create root cohort - let root: Cohort = await createCohort( + let root: ICohort = await createCohort( niceName(idTypeConfig.idType), 'All', true, @@ -369,6 +370,7 @@ export class CohortApp { root.setLabels(idTypeConfig.idType, panel.id); } root.isInitial = true; // set cohort as root + // referenceCohort = reference; // save reference cohort this.rootCohort = root; const rootAsJSON = root.toProvenanceJSON(); @@ -460,7 +462,6 @@ export class CohortApp { // try { // const databases: Array = await AppContext.getInstance().getAPIJSON('/tdp/db/'); // log.debug('Available databases: ', databases); - // // get all idtypes via the views // if (databases.length > 0) { // for (const db of databases) { @@ -485,7 +486,6 @@ export class CohortApp { // } // return genericViews; // } - private _showChangeLayoutOptions(show: boolean) { const screenControls = this.$node.select('.control-bar').select('.screen-controls').node() as HTMLDivElement; screenControls.toggleAttribute('hidden', !show); @@ -580,144 +580,3 @@ export class CohortApp { this.$node.style('grid-template-rows', gridRowTemplate); } } - -/** - * The app for this website, embeds our Cohort App - */ -export class App extends ATDPApplication { - constructor(name: string, loginDialog: string, showCookieDisclaimer = true) { - super({ - prefix: 'coral', - name, - loginForm: loginDialog, - /** - * Link to help and show help in `Coral at a Glance` page instead - */ - showHelpLink: `${`${window.location.href.split('app/')[0]}#/help`}`, - showCookieDisclaimer, - /** - * Show content in the `Coral at a Glance` page instead - */ - showAboutLink: false, - /** - * Show content in the `Coral at a Glance` page instead - */ - showReportBugLink: false, - clientConfig: { - contact: { - href: 'https://github.com/Caleydo/Coral/issues/', - label: 'report an issue', - }, - }, - }); - - console.log('clientConfig', this.options.clientConfig); - console.log('clientConfig contact', this.options.clientConfig?.contact); - } - - protected createApp(graph: ProvenanceGraph, manager: CLUEGraphManager, main: HTMLElement): CohortApp | PromiseLike { - log.debug('Create App'); - this.replaceHelpIcon(); - return new CohortApp(graph, manager, main, this.options).init(); - } - - private replaceHelpIcon() { - const helpButton = select(this.header.rightMenu).select('li[data-header="helpLink"]'); - helpButton.select('span.fa-stack').remove(); - helpButton.select('a.nav-link').insert('i', ':first-child').attr('class', 'fa fa-question-circle'); - } - - protected initSessionImpl(app: CohortApp) { - log.debug('initSessionImpl. Is Graph empty?', app.graph.isEmpty); - this.jumpToStoredOrLastState(); - } -} - -export class CohortSelectionListener { - private static instance: CohortSelectionListener; - - public taskview: Taskview; - - selection: Cohort[] = []; - - firstCohort = true; - - public static get() { - return CohortSelectionListener.instance; - } - - static init(eventTarget: Node, app: CohortApp) { - if (CohortSelectionListener.instance) { - CohortSelectionListener.instance.eventTarget.removeEventListener(COHORT_SELECTION_EVENT_TYPE, CohortSelectionListener.instance.handleSelectionEvent); // remove listener - CohortSelectionListener.instance.selection.forEach((cht) => (cht.selected = false)); // deselect - delete CohortSelectionListener.instance; // destroy - } - CohortSelectionListener.instance = new CohortSelectionListener(eventTarget, app); - } - - static reset() { - if (CohortSelectionListener.instance) { - CohortSelectionListener.instance.selection = []; - CohortSelectionListener.instance.firstCohort = true; - } - } - - private constructor(private eventTarget: Node, private app: CohortApp) { - eventTarget.addEventListener(COHORT_SELECTION_EVENT_TYPE, (ev) => this.handleSelectionEvent(ev as CohortSelectionEvent)); // arrow function to keep "this" working in eventhandler - } - - public handleSelectionEvent(ev: CohortSelectionEvent) { - const clickedCht = ev.detail.cohort; - const { replaceSelection } = ev.detail; - - if (!clickedCht.representation.getRepresentation().classList.contains('preview')) { - // if true deselect all current selected cohorts - if (replaceSelection) { - const toDeselect = this.selection.splice(0, this.selection.length); // clear array and get a copy with cohorts to deselect - toDeselect.forEach((cht) => (cht.selected = false)); // deselect all - } - - // Update selection array: - if (this.selection.indexOf(clickedCht) > -1) { - // already selected --> remove - removeFromArray(this.selection, clickedCht); - clickedCht.colorTaskView = null; - clickedCht.selected = false; - if ((clickedCht as InputCohort).outputCohorts !== undefined) { - delete (clickedCht as InputCohort).outputCohorts; - } - log.info(`De-Selected "${clickedCht.label}"`); - } else { - if (this.firstCohort) { - // this is the first cohort the user selected - this.app.setAppGridLayout('split'); // show bottom - this.firstCohort = false; - } - - this.selection.push(clickedCht); - clickedCht.colorTaskView = null; - clickedCht.selected = true; - log.info(`Selected "${clickedCht.label}"`); - } - - // set selection in taskview - this.taskview.setInputCohorts(this.selection); - - this.selection.forEach((cht) => (cht.selected = true)); - this.taskview.clearOutput(); // every selection change clears the output cohorts - } - } -} - -export interface IPanelDesc { - id: string; - description: string; - species: string; -} - -export interface IDatasetDesc { - source: IEntitySourceConfig; - panel?: IPanelDesc; - rootCohort: IElementProvJSONCohort; - chtOverviewElements: IElementProvJSON[]; -} diff --git a/src/app/CoralSelectionListener.ts b/src/app/CoralSelectionListener.ts new file mode 100644 index 0000000..80dce33 --- /dev/null +++ b/src/app/CoralSelectionListener.ts @@ -0,0 +1,81 @@ +import type { CoralApp } from './CoralApp'; +import type Taskview from '../Taskview/Taskview'; +import { log, removeFromArray } from '../util'; +import { CohortSelectionEvent, COHORT_SELECTION_EVENT_TYPE } from '../base/events'; +import type { ICohort, IInputCohort } from './interfaces'; + +export class CohortSelectionListener { + private static instance: CohortSelectionListener; + + public taskview: Taskview; + + selection: ICohort[] = []; + + firstCohort = true; + + public static get() { + return CohortSelectionListener.instance; + } + + static init(eventTarget: Node, app: CoralApp) { + if (CohortSelectionListener.instance) { + CohortSelectionListener.instance.eventTarget.removeEventListener(COHORT_SELECTION_EVENT_TYPE, CohortSelectionListener.instance.handleSelectionEvent); // remove listener + CohortSelectionListener.instance.selection.forEach((cht) => (cht.selected = false)); // deselect + delete CohortSelectionListener.instance; // destroy + } + CohortSelectionListener.instance = new CohortSelectionListener(eventTarget, app); + } + + static reset() { + if (CohortSelectionListener.instance) { + CohortSelectionListener.instance.selection = []; + CohortSelectionListener.instance.firstCohort = true; + } + } + + private constructor(private eventTarget: Node, private app: CoralApp) { + eventTarget.addEventListener(COHORT_SELECTION_EVENT_TYPE, (ev) => this.handleSelectionEvent(ev as CohortSelectionEvent)); // arrow function to keep "this" working in eventhandler + } + + public handleSelectionEvent(ev: CohortSelectionEvent) { + const clickedCht = ev.detail.cohort; + const { replaceSelection } = ev.detail; + + if (!clickedCht.representation.getRepresentation().classList.contains('preview')) { + // if true deselect all current selected cohorts + if (replaceSelection) { + const toDeselect = this.selection.splice(0, this.selection.length); // clear array and get a copy with cohorts to deselect + toDeselect.forEach((cht) => (cht.selected = false)); // deselect all + } + + // Update selection array: + if (this.selection.indexOf(clickedCht) > -1) { + // already selected --> remove + removeFromArray(this.selection, clickedCht); + clickedCht.colorTaskView = null; + clickedCht.selected = false; + if ((clickedCht as IInputCohort).outputCohorts !== undefined) { + delete (clickedCht as IInputCohort).outputCohorts; + } + log.info(`De-Selected "${clickedCht.label}"`); + } else { + if (this.firstCohort) { + // this is the first cohort the user selected + this.app.setAppGridLayout('split'); // show bottom + this.firstCohort = false; + } + + this.selection.push(clickedCht); + clickedCht.colorTaskView = null; + clickedCht.selected = true; + log.info(`Selected "${clickedCht.label}"`); + } + + // set selection in taskview + this.taskview.setInputCohorts(this.selection); + + this.selection.forEach((cht) => (cht.selected = true)); + this.taskview.clearOutput(); // every selection change clears the output cohorts + } + } +} diff --git a/src/app/index.ts b/src/app/index.ts new file mode 100644 index 0000000..2bcbc68 --- /dev/null +++ b/src/app/index.ts @@ -0,0 +1,4 @@ +export * from './CoralApp'; +export * from './Coral'; +export * from './CoralSelectionListener'; +export * from './interfaces'; diff --git a/src/CohortInterfaces.ts b/src/app/interfaces.ts similarity index 54% rename from src/CohortInterfaces.ts rename to src/app/interfaces.ts index 926b3c5..0c74bd7 100644 --- a/src/CohortInterfaces.ts +++ b/src/app/interfaces.ts @@ -1,8 +1,57 @@ -import { IDType, IServerColumn } from 'tdp_core'; -import { Cohort } from './Cohort'; -import { IAttribute, IAttributeJSON } from './data/Attribute'; -import { IEqualsList, INumRange } from './rest'; -import { InputCohort } from './Taskview/Taskview'; +import { IDType, IDTypeLike } from 'visyn_core/idtype'; +import { IServerColumn, IRow } from 'visyn_core/base'; +import { IAllFilters } from 'tdp_core'; +import type { IEntitySourceConfig } from '../config/entities'; +import { + ICohortDepletionScoreFilterParams, + ICohortEqualsFilterParams, + ICohortGeneEqualsFilterParams, + ICohortGeneNumFilterParams, + ICohortNumFilterParams, + ICohortPanelAnnotationFilterParams, + IEqualsList, + INumRange, +} from '../base/interfaces'; +import type { IAttribute, IAttributeJSON } from '../data/IAttribute'; + +export enum ECloneFilterTypes { + none, + equals, + range, + geneScoreRange, + geneScoreEquals, + depletionScoreRange, + panelAnnotation, +} + +export interface ICohortClassBasicValues { + id: string; + dbId: number; + labelOne: string; + labelTwo: string; +} + +export interface ICohortClassDatabaseValues { + database: string; + schema: string; + table: string; + view: string; + idType: IDTypeLike; + idColumn: IServerColumn; +} + +export interface IPanelDesc { + id: string; + description: string; + species: string; +} + +export interface IDatasetDesc { + source: IEntitySourceConfig; + panel?: IPanelDesc; + rootCohort: IElementProvJSONCohort; + chtOverviewElements: IElementProvJSON[]; +} /** * Enumeration for the different types of task @@ -25,14 +74,14 @@ export enum TaskType { * Interface for every element in the overview (except the paths between the elements) */ -export enum ElementProvType { +export enum EElementProvType { Cohort = 'Cohort', TaskSplit = 'Task-Split', TaskFilter = 'Task-Filter', } export interface IProvAttrAndValuesCohort { - values: Array; + values: (INumRange[] | IEqualsList)[]; view: string; database: string; idType: IDType; @@ -47,7 +96,7 @@ export interface IProvAttrAndValuesTask { export interface IElementProvJSON { id: string; - type: ElementProvType; + type: EElementProvType; label: string; parent: string[]; children: string[]; @@ -72,16 +121,87 @@ export interface IElement { toProvenanceJSON(): IElementProvJSON; } +export interface IBloodlineElement { + obj: IElement; + elemType: string; + label: string; + size: number; +} + /** * Interface for a cohort in the overview */ export interface ICohort extends IElement { + readonly idType: IDType; + readonly idColumn: IServerColumn; + + table: string; + selected: boolean; representation: ICohortRep; + id: string; dbId: number; - values: Array; + database: string; + values: (INumRange[] | IEqualsList)[]; isInitial: boolean; sizeReference: number; + get size(): Promise; + getRetrievedSize(): number; + schema: string; + view: string; + colorTaskView: string; + isClone: boolean; + + label: string; + setLabels(labelOne: string, labelTwo: string); + get labelOne(): string; + get labelTwo(): string; + getHTMLLabel(): string; + toProvenanceJSON(): IElementProvJSONCohort; + + // getTaskChildren(): Task[]; // TODO create ITask interface and use here + + parents: IElement[]; + setCohortParents(chtParents: ICohort[]); + getCohortParents(): ICohort[]; + + children: IElement[]; + getCohortChildren(): ICohort[]; + + filters: IAllFilters; + hasfilterConflict(): boolean; + usedFilter: ECloneFilterTypes; + usedFilterParams: + | ICohortEqualsFilterParams + | ICohortNumFilterParams + | ICohortGeneNumFilterParams + | ICohortDepletionScoreFilterParams + | ICohortPanelAnnotationFilterParams; + + clone( + usedFilter: ECloneFilterTypes, + filterParams: + | ICohortEqualsFilterParams + | ICohortNumFilterParams + | ICohortGeneNumFilterParams + | ICohortGeneEqualsFilterParams + | ICohortDepletionScoreFilterParams + | ICohortPanelAnnotationFilterParams, + ): ICohort; + + get data(): Promise; + + getBloodline(): IBloodlineElement[]; + updateBloodline(); +} + +export interface IInputCohort extends ICohort { + outputCohorts: IOutputCohort[]; +} + +export interface IOutputCohort extends ICohort { + isLastOutputCohort: boolean; + isFirstOutputCohort: boolean; } /** @@ -169,8 +289,8 @@ export interface ISetLabelFunc { } export interface ITaskParams { - inputCohorts: InputCohort[]; // combine can have multiple - outputCohorts: Cohort[]; + inputCohorts: IInputCohort[]; // combine can have multiple + outputCohorts: IOutputCohort[]; type: TaskType; label: string; } diff --git a/src/utilCustomEvents.ts b/src/base/events.ts similarity index 83% rename from src/utilCustomEvents.ts rename to src/base/events.ts index 3a29d3d..5849aa3 100644 --- a/src/utilCustomEvents.ts +++ b/src/base/events.ts @@ -1,13 +1,12 @@ -import { Cohort } from './Cohort'; -import { ITaskParams } from './CohortInterfaces'; -import { IAttribute } from './data/Attribute'; -import { Task } from './Tasks'; -import { AColumn } from './Taskview/columns/AColumn'; -import { IFilterDesc, SortType } from './util'; +import type { ICohort, ITaskParams } from '../app/interfaces'; +import type { IAttribute } from '../data/IAttribute'; +import type { Task } from '../Tasks'; +import type { AColumn } from '../Taskview/columns/AColumn'; +import { IFilterDesc, SortType } from '../util'; export const COHORT_REMOVE_EVENT_TYPE = 'cht:remove'; -export class CohortRemoveEvent extends CustomEvent<{ cohort: Cohort }> { - constructor(cohort: Cohort) { +export class CohortRemoveEvent extends CustomEvent<{ cohort: ICohort }> { + constructor(cohort: ICohort) { super(COHORT_REMOVE_EVENT_TYPE, { detail: { cohort }, bubbles: true }); } } @@ -20,8 +19,8 @@ export class TaskRemoveEvent extends CustomEvent<{ task: Task }> { } export const COHORT_SELECTION_EVENT_TYPE = 'cht:select'; -export class CohortSelectionEvent extends CustomEvent<{ cohort: Cohort; replaceSelection: boolean }> { - constructor(cohort: Cohort, replaceSelection = false) { +export class CohortSelectionEvent extends CustomEvent<{ cohort: ICohort; replaceSelection: boolean }> { + constructor(cohort: ICohort, replaceSelection = false) { super(COHORT_SELECTION_EVENT_TYPE, { detail: { cohort, replaceSelection }, bubbles: true }); } } @@ -41,8 +40,8 @@ export class ColumnSortEvent extends CustomEvent<{ type: SortType; sortInputChts } export const CREATE_OUTPUT_COHORT_EVENT_TYPE = 'cht:create:output'; -export class CreateOutputCohortEvent extends CustomEvent<{ cohort: Cohort; origin?: Cohort }> { - constructor(cohort: Cohort, originCohort?: Cohort) { +export class CreateOutputCohortEvent extends CustomEvent<{ cohort: ICohort; origin?: ICohort }> { + constructor(cohort: ICohort, originCohort?: ICohort) { super(CREATE_OUTPUT_COHORT_EVENT_TYPE, { detail: { cohort, origin: originCohort }, bubbles: true }); } } @@ -66,8 +65,8 @@ export class SplitEvent extends CustomEvent<{ desc: IFilterDesc[] }> { } export const CONFIRM_OUTPUT_EVENT_TYPE = 'cht:output:confirm'; -export class ConfirmOutputEvent extends CustomEvent<{ cohorts: Cohort[] }> { - constructor(cohorts: Cohort[]) { +export class ConfirmOutputEvent extends CustomEvent<{ cohorts: ICohort[] }> { + constructor(cohorts: ICohort[]) { super(CONFIRM_OUTPUT_EVENT_TYPE, { detail: { cohorts }, bubbles: true }); } } diff --git a/src/base/index.ts b/src/base/index.ts new file mode 100644 index 0000000..05123d5 --- /dev/null +++ b/src/base/index.ts @@ -0,0 +1,2 @@ +export * from './rest'; +export * from './interfaces'; diff --git a/src/base/interfaces.ts b/src/base/interfaces.ts new file mode 100644 index 0000000..013b065 --- /dev/null +++ b/src/base/interfaces.ts @@ -0,0 +1,236 @@ +import type { IParams } from 'tdp_core'; + +export interface ICohortDBParams extends IParams { + name: string; + isInitial: number; // 0 = false, 1 = true + previous: number; + database: string; + schema: string; + table: string; +} + +export interface ICohortEqualsFilterParams extends IParams, IEqualsList { + cohortId: number; + attribute: string; + numeric: 'true' | 'false'; +} + +export interface ICohortDBWithEqualsFilterParams extends ICohortEqualsFilterParams { + name: string; +} + +export interface ICohortNumFilterParams { + cohortId: number; + attribute: string; + ranges: Array; +} + +export interface ICohortGeneNumFilterParams extends ICohortNumFilterParams { + table: string; + ensg: string; +} + +export interface ICohortGeneEqualsFilterParams extends ICohortEqualsFilterParams { + table: string; + ensg: string; +} + +export interface ICohortDBWithNumFilterParams extends ICohortNumFilterParams { + name: string; +} + +export const valueListDelimiter = '⸱'; + +export interface IEqualsList { + values: Array | Array; +} + +/** + * Type Guard 💂‍♂️ helper because interfaces can't be checked if instanceof + * @param filter + */ +export function isEqualsList(filter: INumRange | IEqualsList): filter is IEqualsList { + return (filter as IEqualsList).values && Array.isArray((filter as IEqualsList).values); // checking the type of the array requires to check every item but this should be sufficently safe +} + +export enum NumRangeOperators { + lt = 'lt', + lte = 'lte', + gt = 'gt', + gte = 'gte', +} +export interface INumRange { + operatorOne: NumRangeOperators; + valueOne: number | 'null'; + operatorTwo?: NumRangeOperators; + valueTwo?: number | 'null'; +} + +/** + * Type Guard 💂‍♂️ helper because interfaces can't be checked if instanceof + * @param filter + */ +export function isNumRangeFilter(filter: INumRange | IEqualsList): filter is INumRange { + return (filter as INumRange).operatorOne !== undefined && (filter as INumRange).valueOne !== undefined; // check the non-optional properties +} +export interface ICohortDBDataParams extends IParams { + cohortId: number; + attribute?: string; +} + +export interface ICohortDBSizeParams extends IParams { + cohortId: number; +} + +export interface ICohortDBCohortDataParams extends IParams { + cohortIds: number[]; +} + +export interface ICohortDBUpdateName extends IParams { + cohortId: number; + name: string; +} +export interface ICohortDBGeneScoreParams extends IParams { + cohortId: number; + table: string; + attribute: string; + ensg: string; +} + +export interface ICohortDBDepletionScoreParams extends ICohortDBGeneScoreParams { + depletionscreen: string; +} + +export interface ICohortDBPanelAnnotationParams extends IParams { + cohortId: number; + panel: string; +} + +export interface ICohortDepletionScoreFilterParams { + cohortId: number; + table: string; + attribute: string; + ensg: string; + depletionscreen: string; + ranges: Array; +} + +export interface ICohortDBWithGeneNumFilterParams extends ICohortDBWithNumFilterParams { + table: string; + ensg: string; +} + +export interface ICohortDBWithGeneEqualsFilterParams extends ICohortDBWithEqualsFilterParams { + table: string; + ensg: string; +} + +export interface ICohortDBWithDepletionScoreFilterParams extends ICohortDBWithGeneNumFilterParams { + depletionscreen: string; +} + +export interface ICohortDBWithPanelAnnotationFilterParams extends IParams { + cohortId: number; + name: string; + panel: string; + values: Array; +} + +export interface ICohortPanelAnnotationFilterParams extends IParams { + cohortId: number; + panel: string; + values: Array; +} + +export interface ICohortDBWithTreatmentFilterParams extends IParams { + cohortId: number; + name: string; + baseAgent: boolean; + agent?: Array; + regimen?: number; +} + +export enum CohortRoutes { + create = 'create', + createUseEqulasFilter = 'createUseEqulasFilter', + dataUseEqulasFilter = 'dataUseEqulasFilter', + sizeUseEqulasFilter = 'sizeUseEqulasFilter', + createUseNumFilter = 'createUseNumFilter', + dataUseNumFilter = 'dataUseNumFilter', + sizeUseNumFilter = 'sizeUseNumFilter', + createUseGeneNumFilter = 'createUseGeneNumFilter', + dataUseGeneNumFilter = 'dataUseGeneNumFilter', + sizeUseGeneNumFilter = 'sizeUseGeneNumFilter', + createUseGeneEqualsFilter = 'createUseGeneEqualsFilter', + sizeUseGeneEqualsFilter = 'sizeUseGeneEqualsFilter', + dataUseGeneEqualsFilter = 'dataUseGeneEqualsFilter', + cohortData = 'cohortData', + size = 'size', + getDBCohorts = 'getDBCohorts', + updateCohortName = 'updateCohortName', + geneScore = 'geneScore', + celllineDepletionScore = 'celllineDepletionScore', + createUseDepletionScoreFilter = 'createUseDepletionScoreFilter', + dataUseDepletionScoreFilter = 'dataUseDepletionScoreFilter', + sizeUseDepletionScoreFilter = 'sizeUseDepletionScoreFilter', + panelAnnotation = 'panelAnnotation', + createUsePanelAnnotationFilter = 'createUsePanelAnnotationFilter', + dataUsePanelAnnotationFilter = 'dataUsePanelAnnotationFilter', + sizeUsePanelAnnotationFilter = 'sizeUsePanelAnnotationFilter', + hist = 'hist', + createUseTreatmentFilter = 'createUseTreatmentFilter', +} + +export interface IDataBaseToDisplay { + value: string | number; + name: string; +} + +// copy from tdp_publicdb/src/constants.ts +// for 'Copy Number Class' +// table: copynumber, attribtue: copynumberclass +export const mapCopyNumberCat: IDataBaseToDisplay[] = [ + { value: 2, name: 'Amplification' }, + { value: -2, name: 'Deep Deletion' }, + // {value: -1, name: 'Heterozygous deletion'}, + { value: 0, name: 'NORMAL' }, + // {value: 1, name: 'Low level amplification'}, + // {value: 2, name: 'High level amplification'}, + { value: 'null', name: 'Unknown' }, + { value: '!null', name: '!null' }, +]; + +// for 'AA Mutated' and 'DNA Mutated' +// table: mutation, attribute: aa_mutated / dna_mutated +export const mapMutationCat: IDataBaseToDisplay[] = [ + { value: 'true', name: 'Mutated' }, + { value: 'false', name: 'Non Mutated' }, + { value: 'null', name: 'Unknown' }, + { value: '!null', name: '!null' }, +]; + +/** + * Interface for the cohort tuple (row) in the DB + */ +export interface ICohortRow { + id: number; + name: string; + entity_database: string; + entity_schema: string; + entity_table: string; + is_initial: number; +} + +export enum DataMappingDirection { + DB2Display, + Display2DB, +} + +export enum HistRouteType { + dataCat = 'dataCat', + dataNum = 'dataNum', + geneScoreCat = 'geneScoreCat', + geneScoreNum = 'geneScoreNum', + depletionScore = 'depletionScore', + panelAnnotation = 'panelAnnotation', +} diff --git a/src/rest.ts b/src/base/rest.ts similarity index 71% rename from src/rest.ts rename to src/base/rest.ts index d186ec6..2236158 100644 --- a/src/rest.ts +++ b/src/base/rest.ts @@ -1,231 +1,38 @@ -import { Ajax, AppContext, IParams, IRow } from 'tdp_core'; -import { deepCopy, log } from './util'; - -export interface ICohortDBParams extends IParams { - name: string; - isInitial: number; // 0 = false, 1 = true - previous: number; - database: string; - schema: string; - table: string; -} - -export interface ICohortEqualsFilterParams extends IParams, IEqualsList { - cohortId: number; - attribute: string; - numeric: 'true' | 'false'; -} - -export interface ICohortDBWithEqualsFilterParams extends ICohortEqualsFilterParams { - name: string; -} - -export interface ICohortNumFilterParams { - cohortId: number; - attribute: string; - ranges: Array; -} - -export interface ICohortGeneNumFilterParams extends ICohortNumFilterParams { - table: string; - ensg: string; -} - -export interface ICohortGeneEqualsFilterParams extends ICohortEqualsFilterParams { - table: string; - ensg: string; -} - -export interface ICohortDBWithNumFilterParams extends ICohortNumFilterParams { - name: string; -} - -export const valueListDelimiter = '⸱'; - -export interface IEqualsList { - values: Array | Array; -} - -/** - * Type Guard 💂‍♂️ helper because interfaces can't be checked if instanceof - * @param filter - */ -export function isEqualsList(filter: INumRange | IEqualsList): filter is IEqualsList { - return (filter as IEqualsList).values && Array.isArray((filter as IEqualsList).values); // checking the type of the array requires to check every item but this should be sufficently safe -} - -export enum NumRangeOperators { - lt = 'lt', - lte = 'lte', - gt = 'gt', - gte = 'gte', -} -export interface INumRange { - operatorOne: NumRangeOperators; - valueOne: number | 'null'; - operatorTwo?: NumRangeOperators; - valueTwo?: number | 'null'; -} - -/** - * Type Guard 💂‍♂️ helper because interfaces can't be checked if instanceof - * @param filter - */ -export function isNumRangeFilter(filter: INumRange | IEqualsList): filter is INumRange { - return (filter as INumRange).operatorOne !== undefined && (filter as INumRange).valueOne !== undefined; // check the non-optional properties -} -export interface ICohortDBDataParams extends IParams { - cohortId: number; - attribute?: string; -} - -export interface ICohortDBSizeParams extends IParams { - cohortId: number; -} - -export interface ICohortDBCohortDataParams extends IParams { - cohortIds: number[]; -} - -export interface ICohortDBUpdateName extends IParams { - cohortId: number; - name: string; -} -export interface ICohortDBGeneScoreParams extends IParams { - cohortId: number; - table: string; - attribute: string; - ensg: string; -} - -export interface ICohortDBDepletionScoreParams extends ICohortDBGeneScoreParams { - depletionscreen: string; -} - -export interface ICohortDBPanelAnnotationParams extends IParams { - cohortId: number; - panel: string; -} - -export interface ICohortDepletionScoreFilterParams { - cohortId: number; - table: string; - attribute: string; - ensg: string; - depletionscreen: string; - ranges: Array; -} - -export interface ICohortDBWithGeneNumFilterParams extends ICohortDBWithNumFilterParams { - table: string; - ensg: string; -} - -export interface ICohortDBWithGeneEqualsFilterParams extends ICohortDBWithEqualsFilterParams { - table: string; - ensg: string; -} - -export interface ICohortDBWithDepletionScoreFilterParams extends ICohortDBWithGeneNumFilterParams { - depletionscreen: string; -} - -export interface ICohortDBWithPanelAnnotationFilterParams extends IParams { - cohortId: number; - name: string; - panel: string; - values: Array; -} - -export interface ICohortPanelAnnotationFilterParams extends IParams { - cohortId: number; - panel: string; - values: Array; -} - -export interface ICohortDBWithTreatmentFilterParams extends IParams { - cohortId: number; - name: string; - baseAgent: boolean; - agent?: Array; - regimen?: number; -} - -enum CohortRoutes { - create = 'create', - createUseEqulasFilter = 'createUseEqulasFilter', - dataUseEqulasFilter = 'dataUseEqulasFilter', - sizeUseEqulasFilter = 'sizeUseEqulasFilter', - createUseNumFilter = 'createUseNumFilter', - dataUseNumFilter = 'dataUseNumFilter', - sizeUseNumFilter = 'sizeUseNumFilter', - createUseGeneNumFilter = 'createUseGeneNumFilter', - dataUseGeneNumFilter = 'dataUseGeneNumFilter', - sizeUseGeneNumFilter = 'sizeUseGeneNumFilter', - createUseGeneEqualsFilter = 'createUseGeneEqualsFilter', - sizeUseGeneEqualsFilter = 'sizeUseGeneEqualsFilter', - dataUseGeneEqualsFilter = 'dataUseGeneEqualsFilter', - cohortData = 'cohortData', - size = 'size', - getDBCohorts = 'getDBCohorts', - updateCohortName = 'updateCohortName', - geneScore = 'geneScore', - celllineDepletionScore = 'celllineDepletionScore', - createUseDepletionScoreFilter = 'createUseDepletionScoreFilter', - dataUseDepletionScoreFilter = 'dataUseDepletionScoreFilter', - sizeUseDepletionScoreFilter = 'sizeUseDepletionScoreFilter', - panelAnnotation = 'panelAnnotation', - createUsePanelAnnotationFilter = 'createUsePanelAnnotationFilter', - dataUsePanelAnnotationFilter = 'dataUsePanelAnnotationFilter', - sizeUsePanelAnnotationFilter = 'sizeUsePanelAnnotationFilter', - hist = 'hist', - createUseTreatmentFilter = 'createUseTreatmentFilter', -} - -interface IDataBaseToDisplay { - value: string | number; - name: string; -} - -// copy from tdp_publicdb/src/constants.ts -// for 'Copy Number Class' -// table: copynumber, attribtue: copynumberclass -const mapCopyNumberCat: IDataBaseToDisplay[] = [ - { value: 2, name: 'Amplification' }, - { value: -2, name: 'Deep Deletion' }, - // {value: -1, name: 'Heterozygous deletion'}, - { value: 0, name: 'NORMAL' }, - // {value: 1, name: 'Low level amplification'}, - // {value: 2, name: 'High level amplification'}, - { value: 'null', name: 'Unknown' }, - { value: '!null', name: '!null' }, -]; - -// for 'AA Mutated' and 'DNA Mutated' -// table: mutation, attribute: aa_mutated / dna_mutated -const mapMutationCat: IDataBaseToDisplay[] = [ - { value: 'true', name: 'Mutated' }, - { value: 'false', name: 'Non Mutated' }, - { value: 'null', name: 'Unknown' }, - { value: '!null', name: '!null' }, -]; - -/** - * Interface for the cohort tuple (row) in the DB - */ -export interface ICohortRow { - id: number; - name: string; - entity_database: string; - entity_schema: string; - entity_table: string; - is_initial: number; -} - -enum DataMappingDirection { - DB2Display, - Display2DB, -} +import { Ajax, AppContext, IRow } from 'visyn_core/base'; +import { IParams } from 'tdp_core'; +import { deepCopy, log } from '../util'; +import { + CohortRoutes, + DataMappingDirection, + HistRouteType, + ICohortDBCohortDataParams, + ICohortDBDataParams, + ICohortDBDepletionScoreParams, + ICohortDBGeneScoreParams, + ICohortDBPanelAnnotationParams, + ICohortDBParams, + ICohortDBSizeParams, + ICohortDBUpdateName, + ICohortDBWithDepletionScoreFilterParams, + ICohortDBWithEqualsFilterParams, + ICohortDBWithGeneEqualsFilterParams, + ICohortDBWithGeneNumFilterParams, + ICohortDBWithNumFilterParams, + ICohortDBWithPanelAnnotationFilterParams, + ICohortDBWithTreatmentFilterParams, + ICohortDepletionScoreFilterParams, + ICohortEqualsFilterParams, + ICohortGeneEqualsFilterParams, + ICohortGeneNumFilterParams, + ICohortNumFilterParams, + ICohortPanelAnnotationFilterParams, + ICohortRow, + IDataBaseToDisplay, + INumRange, + mapCopyNumberCat, + mapMutationCat, + valueListDelimiter, +} from './interfaces'; // maps the database value to a display name function mapDataBaseValueToDisplayName( @@ -567,15 +374,6 @@ export function getCohortPanelAnnotation( return null; } -export enum HistRouteType { - dataCat = 'dataCat', - dataNum = 'dataNum', - geneScoreCat = 'geneScoreCat', - geneScoreNum = 'geneScoreNum', - depletionScore = 'depletionScore', - panelAnnotation = 'panelAnnotation', -} - export interface ICohortDBHistDataParms extends IParams { cohortId: number; attribute: string; diff --git a/src/cohortview.ts b/src/cohortview.ts index 7b286d5..b10594e 100644 --- a/src/cohortview.ts +++ b/src/cohortview.ts @@ -1,25 +1,46 @@ import { IObjectRef, ProvenanceGraph, IDatabaseViewDesc, RestBaseUtils } from 'tdp_core'; -import { CohortApp, CohortSelectionListener } from './app'; -import { Cohort } from './Cohort'; +import { CohortSelectionListener } from './app/CoralSelectionListener'; +import type { CoralApp } from './app/CoralApp'; import { OnboardingManager } from './OnboardingManager'; import { CohortOverview } from './Overview/CohortOverview'; import { RectangleLayout } from './Overview/OverviewLayout'; import Taskview from './Taskview/Taskview'; import { handleDataLoadError, log } from './util'; -import { IEntitySourceConfig } from './utilIdTypes'; +import { IEntitySourceConfig } from './config/entities'; +import { ICohort } from './app/interfaces'; +import { CohortContext } from './CohortContext'; -export let cohortOverview: CohortOverview; -export let taskview: Taskview; +export function destroyOld() { + if (CohortContext.taskview) { + CohortContext.taskview.destroy(); + CohortContext.taskview = null; + } + if (CohortContext.cohortOverview) { + CohortContext.cohortOverview.destroy(); + CohortContext.cohortOverview = null; + } + CohortContext.referenceCohort = null; +} -let referenceCohort: Cohort; +export async function loadViewDescription(database: string, view: string) { + log.debug('getTDPDesc for: db:', database, ' |view: ', view); + try { + const descr: IDatabaseViewDesc = await RestBaseUtils.getTDPDesc(database, view); + log.debug('descr= ', descr); + return descr; + } catch (e) { + handleDataLoadError(e); + return null; + } +} export async function createCohortOverview( graph: ProvenanceGraph, - ref: IObjectRef, + ref: IObjectRef, container: HTMLDivElement, detailView: HTMLDivElement, idTypeConfig: IEntitySourceConfig, - rootCohort: Cohort, + rootCohort: ICohort, ): Promise<{ cohortOV: CohortOverview; taskV: Taskview }> { const viewDescription: IDatabaseViewDesc = await loadViewDescription(idTypeConfig.dbConnectorName, idTypeConfig.viewName); log.debug('retrievedViewDesctiprion', viewDescription); @@ -27,60 +48,21 @@ export async function createCohortOverview( destroyOld(); // set reference/root cohort - referenceCohort = rootCohort; // save reference cohort + CohortContext.referenceCohort = rootCohort; // save reference cohort log.debug('cohortview - root: ', rootCohort); // create Overview - cohortOverview = new CohortOverview(container, graph, ref, new RectangleLayout(130, 50, 50, 50), rootCohort, viewDescription); + CohortContext.cohortOverview = new CohortOverview(container, graph, ref, new RectangleLayout(130, 50, 50, 50), rootCohort, viewDescription); // create Taskview - taskview = new Taskview(detailView, rootCohort); + CohortContext.taskview = new Taskview(detailView, rootCohort); - CohortSelectionListener.get().taskview = taskview; + CohortSelectionListener.get().taskview = CohortContext.taskview; // draw overview in container element - updateOverview(cohortOverview); + CohortContext.cohortOverview.generateOverview(); OnboardingManager.addTip('rootCohort', rootCohort.representation.getRepresentation()); return { - cohortOV: cohortOverview, - taskV: taskview, + cohortOV: CohortContext.cohortOverview, + taskV: CohortContext.taskview, }; } - -export function getRootCohort(): Cohort { - return referenceCohort; -} - -export function destroyOld() { - if (taskview) { - taskview.destroy(); - taskview = null; - } - if (cohortOverview) { - cohortOverview.destroy(); - cohortOverview = null; - } - referenceCohort = null; -} - -export function getCohortOverview(): CohortOverview { - return cohortOverview; -} - -export function getTaskview(): Taskview { - return taskview; -} - -export function updateOverview(overview: CohortOverview) { - overview.generateOverview(); -} - -export async function loadViewDescription(database: string, view: string) { - log.debug('getTDPDesc for: db:', database, ' |view: ', view); - try { - const descr: IDatabaseViewDesc = await RestBaseUtils.getTDPDesc(database, view); - log.debug('descr= ', descr); - return descr; - } catch (e) { - handleDataLoadError(e); - } -} diff --git a/src/colors.ts b/src/colors.ts deleted file mode 100644 index 9f504a3..0000000 --- a/src/colors.ts +++ /dev/null @@ -1,18 +0,0 @@ -// equals colors in src/scss/abstracts/_variables.scss -export const colors = { - selectedColor: '#FFC340', - hoverColor: '#52C0CC', - searchbarHoverColor: '#D4D4D4', - - barColor: '#595959', - barBackgroundColor: '#FFF', - cohortBackgroundColor: '#EFEFEF', - - lighterTextColor: '#737373', - textColor: ' #333333', - backgroundColor: '#FFF', - - lightBorder: '#d4d4d4', - mediumBorder: '#AAA', - darkBorder: '#333', -}; diff --git a/src/common/config.ts b/src/common/config.ts index f7d1581..d78257a 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -3,7 +3,8 @@ */ import { Categories } from 'tdp_publicdb'; -import { IServerColumn, ColumnDescUtils, IAdditionalColumnDesc } from 'tdp_core'; +import { IServerColumn } from 'visyn_core/base'; +import { ColumnDescUtils, IAdditionalColumnDesc } from 'tdp_core'; /** * maximal number of rows in which just the subset if fetched instead of all @@ -172,6 +173,10 @@ export const tissue: IDataSourceConfig = { }, }; +function toLineUpCategories(arr: { name: string; value: any; color: string }[]) { + return arr.map((a) => ({ label: a.name, name: String(a.value), color: a.color })); +} + function toChromosomes(categories: string[]) { const order = new Map(); for (let i = 1; i <= 22; ++i) { @@ -257,6 +262,8 @@ export function chooseDataSource(desc: any): IDataSourceConfig { return tissue; case gene.name: return gene; + default: + return null; } } @@ -495,19 +502,6 @@ export const drug: IDataSourceConfig = { export const dataTypes: IDataTypeConfig[] = [expression, copyNumber, mutation]; -function toLineUpCategories(arr: { name: string; value: any; color: string }[]) { - return arr.map((a) => ({ label: a.name, name: String(a.value), color: a.color })); -} - -/** - * splits strings in the form of "DATA_TYPE-DATA_SUBTYPE" and returns the corresponding DATA_TYPE and DATA_SUBTYPE objects - */ -export function splitTypes(toSplit: string): { dataType: IDataTypeConfig; dataSubType: IDataSubtypeConfig } { - console.assert(toSplit.includes('-'), 'The splitTypes method requires the string to contain a dash ("-")'); - const [type, subtype] = toSplit.split('-'); - return resolveDataTypes(type, subtype); -} - export function resolveDataTypes(dataTypeId: string, dataSubTypeId: string) { let dataType: IDataTypeConfig; @@ -527,10 +521,21 @@ export function resolveDataTypes(dataTypeId: string, dataSubTypeId: string) { case drugScreen.id: dataType = drugScreen; break; + default: + dataType = null; } - const dataSubType = dataType.dataSubtypes.find((element) => element.id === dataSubTypeId); + const dataSubType = dataType?.dataSubtypes?.find((element) => element.id === dataSubTypeId); return { dataType, dataSubType, }; } + +/** + * splits strings in the form of "DATA_TYPE-DATA_SUBTYPE" and returns the corresponding DATA_TYPE and DATA_SUBTYPE objects + */ +export function splitTypes(toSplit: string): { dataType: IDataTypeConfig; dataSubType: IDataSubtypeConfig } { + console.assert(toSplit.includes('-'), 'The splitTypes method requires the string to contain a dash ("-")'); + const [type, subtype] = toSplit.split('-'); + return resolveDataTypes(type, subtype); +} diff --git a/src/common/forms.ts b/src/common/forms.ts index 2261ffa..dc4895f 100644 --- a/src/common/forms.ts +++ b/src/common/forms.ts @@ -3,7 +3,8 @@ */ import { SpeciesUtils, FormSubtype } from 'tdp_publicdb'; -import { FormElementType, IFormElement, IFormSelectOption, ValueCache, RestStorageUtils, LineupUtils, RestBaseUtils, IServerColumn } from 'tdp_core'; +import { IServerColumn } from 'visyn_core/base'; +import { FormElementType, IFormElement, IFormSelectOption, ValueCache, RestStorageUtils, LineupUtils, RestBaseUtils } from 'tdp_core'; import { gene, IDataSourceConfig, tissue, cellline, dataSources, dataTypes, dataSubtypes, depletion, drugScreen } from './config'; import { GeneUtils } from './GeneUtils'; @@ -157,7 +158,7 @@ export const FORM_GENE_FILTER = { RestBaseUtils.getTDPData<{ text: string }>(gene.db, 'gene_unique_all', { column: 'biotype', species: SpeciesUtils.getSelectedSpecies(), - }).then((r) => r.map((d) => d.text)), + }).then((r) => r.map((v) => v.text)), ), options: { placeholder: 'Start typing...', @@ -246,7 +247,7 @@ function generateTissueSpecificFilter(d: IDataSourceConfig) { RestBaseUtils.getTDPData<{ text: string }>(d.db, `${d.base}_unique_all`, { column: 'tumortype_adjacent', species: SpeciesUtils.getSelectedSpecies(), - }).then((r) => r.map((d) => d.text)), + }).then((r) => r.map((v) => v.text)), ), options: { placeholder: 'Start typing...', @@ -262,7 +263,7 @@ function generateTissueSpecificFilter(d: IDataSourceConfig) { RestBaseUtils.getTDPData<{ text: string }>(d.db, `${d.base}_unique_all`, { column: 'vendorname', species: SpeciesUtils.getSelectedSpecies(), - }).then((r) => r.map((d) => d.text)), + }).then((r) => r.map((v) => v.text)), ), options: { placeholder: 'Start typing...', @@ -278,7 +279,7 @@ function generateTissueSpecificFilter(d: IDataSourceConfig) { RestBaseUtils.getTDPData<{ text: string }>(d.db, `${d.base}_unique_all`, { column: 'race', species: SpeciesUtils.getSelectedSpecies(), - }).then((r) => r.map((d) => d.text)), + }).then((r) => r.map((v) => v.text)), ), options: { placeholder: 'Start typing...', @@ -294,7 +295,7 @@ function generateTissueSpecificFilter(d: IDataSourceConfig) { RestBaseUtils.getTDPData<{ text: string }>(d.db, `${d.base}_unique_all`, { column: 'ethnicity', species: SpeciesUtils.getSelectedSpecies(), - }).then((r) => r.map((d) => d.text)), + }).then((r) => r.map((v) => v.text)), ), options: { placeholder: 'Start typing...', @@ -310,7 +311,7 @@ function generateTissueSpecificFilter(d: IDataSourceConfig) { RestBaseUtils.getTDPData<{ text: string | boolean }>(d.db, `${d.base}_unique_all`, { column: 'vital_status', species: SpeciesUtils.getSelectedSpecies(), - }).then((r) => r.map((d) => (d.text === true ? 'true' : 'false'))), + }).then((r) => r.map((v) => (v.text === true ? 'true' : 'false'))), ), options: { placeholder: 'Start typing...', @@ -331,7 +332,7 @@ function generateCelllineSpecificFilter(d: IDataSourceConfig) { RestBaseUtils.getTDPData<{ text: string }>(d.db, `${d.base}_unique_all`, { column: 'age_at_surgery', species: SpeciesUtils.getSelectedSpecies(), - }).then((r) => r.map((d) => d.text)), + }).then((r) => r.map((v) => v.text)), ), options: { placeholder: 'Start typing...', @@ -347,7 +348,7 @@ function generateCelllineSpecificFilter(d: IDataSourceConfig) { RestBaseUtils.getTDPData<{ text: string }>(d.db, `${d.base}_unique_all`, { column: 'growth_type', species: SpeciesUtils.getSelectedSpecies(), - }).then((r) => r.map((d) => d.text)), + }).then((r) => r.map((v) => v.text)), ), options: { placeholder: 'Start typing...', @@ -363,7 +364,7 @@ function generateCelllineSpecificFilter(d: IDataSourceConfig) { RestBaseUtils.getTDPData<{ text: string }>(d.db, `${d.base}_unique_all`, { column: 'histology_type', species: SpeciesUtils.getSelectedSpecies(), - }).then((r) => r.map((d) => d.text)), + }).then((r) => r.map((v) => v.text)), ), options: { placeholder: 'Start typing...', @@ -379,7 +380,7 @@ function generateCelllineSpecificFilter(d: IDataSourceConfig) { RestBaseUtils.getTDPData<{ text: string }>(d.db, `${d.base}_unique_all`, { column: 'metastatic_site', species: SpeciesUtils.getSelectedSpecies(), - }).then((r) => r.map((d) => d.text)), + }).then((r) => r.map((v) => v.text)), ), options: { placeholder: 'Start typing...', @@ -395,7 +396,7 @@ function generateCelllineSpecificFilter(d: IDataSourceConfig) { RestBaseUtils.getTDPData<{ text: string }>(d.db, `${d.base}_unique_all`, { column: 'morphology', species: SpeciesUtils.getSelectedSpecies(), - }).then((r) => r.map((d) => d.text)), + }).then((r) => r.map((v) => v.text)), ), options: { placeholder: 'Start typing...', @@ -432,7 +433,7 @@ function generateFilter(d: IDataSourceConfig) { RestBaseUtils.getTDPData<{ text: string }>(d.db, `${d.base}_unique_all`, { column: 'tumortype', species: SpeciesUtils.getSelectedSpecies(), - }).then((r) => r.map((d) => d.text)), + }).then((r) => r.map((v) => v.text)), ), options: { placeholder: 'Start typing...', @@ -448,7 +449,7 @@ function generateFilter(d: IDataSourceConfig) { RestBaseUtils.getTDPData<{ text: string }>(d.db, `${d.base}_unique_all`, { column: 'organ', species: SpeciesUtils.getSelectedSpecies(), - }).then((r) => r.map((d) => d.text)), + }).then((r) => r.map((v) => v.text)), ), options: { placeholder: 'Start typing...', @@ -464,7 +465,7 @@ function generateFilter(d: IDataSourceConfig) { RestBaseUtils.getTDPData<{ text: string }>(d.db, `${d.base}_unique_all`, { column: 'gender', species: SpeciesUtils.getSelectedSpecies(), - }).then((r) => r.map((d) => d.text)), + }).then((r) => r.map((v) => v.text)), ), options: { placeholder: 'Start typing...', @@ -561,6 +562,24 @@ export const FORM_TISSUE_OR_CELLLINE_FILTER = { }, }; +function addEmptyOption(options: IFormSelectOption[]) { + return [{ name: 'None', value: '', data: null }].concat(options); +} + +function selectCategoricalColumn(ds: IDataSourceConfig) { + const dummy: IServerColumn = { + type: 'string', + column: '', + label: '', + categories: [], + min: 0, + max: 1, + }; + const cats = ds.columns(() => dummy).filter((d) => d.type === 'categorical'); + + return cats.map((c) => ({ name: c.label, value: (c).column, data: (c).column })); +} + export const FORM_COLOR_CODING = { type: FormElementType.SELECT, label: 'Color Coding', @@ -582,24 +601,6 @@ export const FORM_COLOR_CODING = { useSession: false, }; -function selectCategoricalColumn(ds: IDataSourceConfig) { - const dummy: IServerColumn = { - type: 'string', - column: '', - label: '', - categories: [], - min: 0, - max: 1, - }; - const cats = ds.columns(() => dummy).filter((d) => d.type === 'categorical'); - - return cats.map((c) => ({ name: c.label, value: (c).column, data: (c).column })); -} - -function addEmptyOption(options: IFormSelectOption[]) { - return [{ name: 'None', value: '', data: null }].concat(options); -} - export const FORM_DATA_HIERARCHICAL_SUBTYPE = { type: FormElementType.SELECT2_MULTIPLE, label: 'Data Type', diff --git a/src/config/colors.ts b/src/config/colors.ts new file mode 100644 index 0000000..2568f45 --- /dev/null +++ b/src/config/colors.ts @@ -0,0 +1,43 @@ +// equals colors in src/scss/abstracts/_variables.scss +export const colors = { + selectedColor: '#FFC340', + hoverColor: '#52C0CC', + searchbarHoverColor: '#D4D4D4', + + barColor: '#595959', + barBackgroundColor: '#FFF', + cohortBackgroundColor: '#EFEFEF', + + lighterTextColor: '#737373', + textColor: ' #333333', + backgroundColor: '#FFF', + + lightBorder: '#d4d4d4', + mediumBorder: '#AAA', + darkBorder: '#333', +}; + +export class CoralColorSchema { + static readonly COLOR_SCHEME = [ + // based on set3: https://vega.github.io/vega/docs/schemes/#set3 + // -> rearranged and without orange, turquose, and grey + '#8dd3c7' /* set3:turquose */, + '#fdb462' /* set3:orange */, + '#b3de69' /* set3:green */, + '#fb8072' /* set3:red */, + '#ffed6f' /* set3:yellow */, + '#bc80bd' /* set3:lila */, + '#80b1d3' /* set3:blue */, + '#fccde5' /* set3:pink */, + '#ccebc5' /* set3:mint */, + '#bebada' /* set3:light lila */, + '#d8b5a5' /* t20: light brown */, + // '#ffffb3' /* set3:light yellow */, + // '#d9d9d9' /* set3:grey */, + ]; + + static get(index: number): string { + const moduloIndex = index % CoralColorSchema.COLOR_SCHEME.length; + return CoralColorSchema.COLOR_SCHEME[moduloIndex]; + } +} diff --git a/src/utilIdTypes.ts b/src/config/entities.ts similarity index 94% rename from src/utilIdTypes.ts rename to src/config/entities.ts index 069cfc8..9f9c1c9 100644 --- a/src/utilIdTypes.ts +++ b/src/config/entities.ts @@ -1,5 +1,5 @@ import { cellline, tissue } from 'tdp_publicdb'; -import { Cohort } from './Cohort'; +import { ICohort } from '../app/interfaces'; export interface IEntitySourceConfig { idType: string; @@ -65,7 +65,7 @@ export const idCovid19: IEntitySourceConfig = { base: 'covid19', }; -export function getIdTypeFromCohort(cht: Cohort): IEntitySourceConfig { +export function getIdTypeFromCohort(cht: ICohort): IEntitySourceConfig { const entitiyTable = cht.table; if (entitiyTable === 'tdp_tissue') { return idTissue; diff --git a/src/data/Attribute.ts b/src/data/Attribute.ts index 1343dc6..c8ef3a5 100644 --- a/src/data/Attribute.ts +++ b/src/data/Attribute.ts @@ -1,15 +1,15 @@ -import { IAllFilters, IServerColumn } from 'tdp_core'; +import { IAllFilters } from 'tdp_core'; +import { IServerColumn } from 'visyn_core/base'; import { IDataSubtypeConfig, IDataTypeConfig, resolveDataTypes } from 'tdp_publicdb'; +import { ICohort } from '../app/interfaces'; import { - Cohort, - createCohortWithDepletionScoreFilter, - createCohortWithEqualsFilter, - createCohortWithGeneEqualsFilter, - createCohortWithGeneNumFilter, - createCohortWithNumFilter, - createCohortWithPanelAnnotationFilter, -} from '../Cohort'; -import { ICohort } from '../CohortInterfaces'; + HistRouteType, + ICohortDBDepletionScoreParams, + ICohortDBGeneScoreParams, + ICohortDBPanelAnnotationParams, + IEqualsList, + INumRange, +} from '../base/interfaces'; import { getCohortData, getCohortDepletionScore, @@ -17,108 +17,23 @@ import { getCohortHist, getCohortPanelAnnotation, getCohortSize, - HistRouteType, - ICohortDBDepletionScoreParams, - ICohortDBGeneScoreParams, ICohortDBHistDataParms, ICohortDBHistPanelParms, ICohortDBHistScoreDepletionParms, ICohortDBHistScoreParms, - ICohortDBPanelAnnotationParams, - IEqualsList, - INumRange, -} from '../rest'; -import { IOption, IScoreOption, IServerColumnOption, ISpecialOption, OptionType } from '../Taskview/SearchBar'; -import { deepCopy, getSessionStorageItem, IAttributeFilter, log, setSessionStorageItem } from '../util'; -import { easyLabelFromFilter, easyLabelFromFilterArray, niceName } from '../utilLabels'; -import { ISpecialAttribute } from './SpecialAttribute'; - -export type AttributeType = 'categorical' | 'number' | 'string'; - -export type ScoreType = 'depletion' | 'expression' | 'copy_number' | 'mutation'; - -export type IdValuePair = { - id: string; - [key: string]: any; -}; - -export interface IAttributeJSON { - option: IOption; - currentDB: string; - currentView: string; -} - -/** - * base type for ServerColumns and ScoreColumn - * id, view, and database are needed for the methods in rest.ts - */ -export interface IAttribute { - /** - * id database access the data - */ - id: string; - - /** - * datakey with which the attributes data can be accessed frontend - * necessary as GeneScoreAttributes have the same id for TPM, Copy Number, etc of the same gene - */ - dataKey: string; - - /** - * view to access the data - */ - view: string; - - /** - * database to access the data - */ - database: string; - - /** - * label of this column for display to the user by default the column name - */ - label: string; - - /** - * column type - */ - type: AttributeType; - - /** - * the categories in case of type=categorical - */ - categories?: string[]; - - /** - * the minimal value in case of type=number - */ - min?: number; - - /** - * the maxmial value in case of type=number - */ - max?: number; - - /** - * wether the attribute is best shown on a log scale - */ - preferLog: boolean; - - getData(cohortDbId: number, filters?: IAllFilters): Promise; // IRow has _id but IScoreRow has not - - getHist(dbId: number, filters?: IAllFilters, bins?: number): Promise<{ bin: string; count: number }[]>; - - getHistWithStorage( - histType: HistRouteType, - params: ICohortDBHistDataParms | ICohortDBHistScoreParms | ICohortDBHistScoreDepletionParms | ICohortDBHistPanelParms, - ): Promise<{ bin: string; count: number }[]>; - - getCount(cohortDbId: number, filters?: IAllFilters): Promise; - - filter(cht: ICohort, filter: INumRange[] | IEqualsList): Promise; - - toJSON(); -} +} from '../base/rest'; +import { + createCohortWithDepletionScoreFilter, + createCohortWithEqualsFilter, + createCohortWithGeneEqualsFilter, + createCohortWithGeneNumFilter, + createCohortWithNumFilter, + createCohortWithPanelAnnotationFilter, +} from '../Cohort'; +import { deepCopy, getSessionStorageItem, IAttributeFilter, setSessionStorageItem } from '../util'; +import { easyLabelFromFilter, easyLabelFromFilterArray, niceName } from '../utils/labels'; +import { AttributeType, IAttribute, IAttributeJSON, IdValuePair, OptionType, ScoreType } from './IAttribute'; +import type { ISpecialAttribute } from './ISpecialAttribute'; export abstract class Attribute implements IAttribute { public preferLog = false; @@ -176,7 +91,7 @@ export abstract class Attribute implements IAttribute { return getCohortSize({ cohortId: cohortDbId }); } - abstract filter(cht: ICohort, filter: INumRange[] | IEqualsList, rangeLabel?: string): Promise; + abstract filter(cht: ICohort, filter: INumRange[] | IEqualsList, rangeLabel?: string): Promise; abstract toJSON(): IAttributeJSON; } @@ -190,7 +105,7 @@ export class ServerColumnAttribute extends Attribute { this.categories = serverColumn.categories as string[]; } - async filter(cht: Cohort, filter: INumRange[] | IEqualsList, rangeLabel?: string): Promise { + async filter(cht: ICohort, filter: INumRange[] | IEqualsList, rangeLabel?: string): Promise { if (Array.isArray(filter)) { // TODO label // const label = rangeLabel ? rangeLabel : filter.map((a) => labelFromFilter(a, this)).join(' / '); @@ -253,7 +168,7 @@ export class SpecialAttribute extends Attribute { return null; } - async filter(cht: Cohort, filter: INumRange[] | IEqualsList, rangeLabel?: string): Promise { + async filter(cht: ICohort, filter: INumRange[] | IEqualsList, rangeLabel?: string): Promise { if (this.spAttribute.overrideFilter) { // this.spAttribute.attributeOption = this.attrOption; // TODO label @@ -296,6 +211,20 @@ export abstract class AScoreAttribute extends Attribute { } } +function subType2Type(subType: string): AttributeType { + // one of number, string, cat, boxplot + switch (subType) { + case 'number': + case 'string': + return subType; + case 'cat': + return 'categorical'; + case 'boxplot': + default: + throw new Error(`No Support for type: ${subType}`); + } +} + /** * Returns the depletion screen (whatever that is) for the given score sub type id * @param subTypeID known subtype ids are ['rsa', 'ataris', 'ceres'] but we are just checking if it is ceres or not. @@ -368,7 +297,7 @@ export class GeneScoreAttribute extends AScoreAttribute { }); } - async filter(cht: Cohort, filter: INumRange[] | IEqualsList, rangeLabel?: string): Promise { + async filter(cht: ICohort, filter: INumRange[] | IEqualsList, rangeLabel?: string): Promise { const param = this.getParam(); if (Array.isArray(filter)) { // TODO label @@ -509,7 +438,7 @@ export class PanelScoreAttribute extends AScoreAttribute { return this.getHistWithStorage(type, params); } - async filter(cht: Cohort, filter: INumRange[] | IEqualsList, rangeLabel?: string): Promise { + async filter(cht: ICohort, filter: INumRange[] | IEqualsList, rangeLabel?: string): Promise { if (Array.isArray(filter)) { throw new Error('not implemented ☠'); } else { @@ -535,66 +464,7 @@ export class PanelScoreAttribute extends AScoreAttribute { } } -export function toAttribute(option: IOption, currentDB, currentView): IAttribute { - if (option.optionType === 'dbc') { - if (option.optionData && (option as ISpecialOption).optionData.spAttribute) { - // Create Special Attribtues - // if (option.optionData.spA === 'treatment') { - log.debug('create special Attribute: ', option.optionId); - log.debug('special Attribute object: ', option.optionData.spAttribute); - return new SpecialAttribute( - option.optionId, - currentView, - currentDB, - (option as ISpecialOption).optionData.spAttribute, - (option as ISpecialOption).optionData.attrOption, - ); - } - // Create Attribute - return new ServerColumnAttribute(option.optionId, currentView, currentDB, (option as IServerColumnOption).optionData.serverColumn); - } - // Create ScoreAttribute - if (option.optionType === 'gene') { - return new GeneScoreAttribute( - option.optionId, - option.optionText, - currentView, - currentDB, - (option as IScoreOption).optionData.type, - (option as IScoreOption).optionData.subType, - ); - } - if (option.optionType === 'panel') { - return new PanelScoreAttribute(option.optionId, currentView, currentDB, 'categorical'); - } -} - -function subType2Type(subType: string): AttributeType { - // one of number, string, cat, boxplot - switch (subType) { - case 'number': - case 'string': - return subType; - case 'cat': - return 'categorical'; - case 'boxplot': - default: - throw new Error(`No Support for type: ${subType}`); - } -} - -export async function multiFilter(baseCohort: Cohort, attributes: IAttribute[], filters: Array): Promise { - if (attributes.length !== filters.length) { - throw new Error(`Number of filters has to match the number of attribtues`); - } - - return multiAttributeFilter( - baseCohort, - attributes.map((attr, i) => ({ attr, range: filters[i] })), - ); -} - -export async function multiAttributeFilter(baseCohort: Cohort, filters: IAttributeFilter[]): Promise { +export async function multiAttributeFilter(baseCohort: ICohort, filters: IAttributeFilter[]): Promise { let newCohort = baseCohort; const labelOne = []; @@ -602,6 +472,8 @@ export async function multiAttributeFilter(baseCohort: Cohort, filters: IAttribu const values = []; for (const attrFilter of filters) { + // TODO: fix me + // eslint-disable-next-line no-await-in-loop newCohort = await attrFilter.attr.filter(newCohort, attrFilter.range); labelOne.push(newCohort.labelOne); labelTwo.push(newCohort.labelTwo); @@ -617,3 +489,14 @@ export async function multiAttributeFilter(baseCohort: Cohort, filters: IAttribu return newCohort; } + +export async function multiFilter(baseCohort: ICohort, attributes: IAttribute[], filters: Array): Promise { + if (attributes.length !== filters.length) { + throw new Error(`Number of filters has to match the number of attribtues`); + } + + return multiAttributeFilter( + baseCohort, + attributes.map((attr, i) => ({ attr, range: filters[i] })), + ); +} diff --git a/src/data/IAttribute.ts b/src/data/IAttribute.ts new file mode 100644 index 0000000..3feb0f1 --- /dev/null +++ b/src/data/IAttribute.ts @@ -0,0 +1,129 @@ +import { IAllFilters } from 'tdp_core'; +import { IServerColumn } from 'visyn_core/base'; +import { IDataSubtypeConfig } from 'tdp_publicdb'; +import { ICohort } from '../app/interfaces'; +import { INumRange, IEqualsList, HistRouteType } from '../base/interfaces'; +import { ICohortDBHistDataParms, ICohortDBHistPanelParms, ICohortDBHistScoreDepletionParms, ICohortDBHistScoreParms } from '../base/rest'; + +export interface ISearchBarGroup { + groupLabel: string; + data: Array; +} + +export type OptionType = 'dbc' | 'gene' | 'panel'; + +export interface IOption { + // id: string; + optionId: string; // e.g. gender or ensg00000141510 + optionType: OptionType; // e.g. dbc or gene + optionText: string; // e.g. Gender or TP53 + optionData?: { + [key: string]: any; // keys are always strings, so we just specify it to be key/value pairs with values of any type + }; +} + +export interface IPanelOption extends IOption { + optionData: { + description: string; // e.g. "Cancer Cell Line Encyclopedia" + species: string; // e.g. human + }; +} + +export type ScoreType = 'depletion' | 'expression' | 'copy_number' | 'mutation'; +export interface IScoreOption extends IOption { + optionData: { + type: ScoreType; // id of = IDataTypeConfig; + subType: IDataSubtypeConfig; + }; +} + +export interface IServerColumnOption extends IOption { + optionData: { + serverColumn: IServerColumn; + }; +} + +export type AttributeType = 'categorical' | 'number' | 'string'; + +export type IdValuePair = { + id: string; + [key: string]: any; +}; + +export interface IAttributeJSON { + option: IOption; + currentDB: string; + currentView: string; +} + +/** + * base type for ServerColumns and ScoreColumn + * id, view, and database are needed for the methods in rest.ts + */ +export interface IAttribute { + /** + * id database access the data + */ + id: string; + + /** + * datakey with which the attributes data can be accessed frontend + * necessary as GeneScoreAttributes have the same id for TPM, Copy Number, etc of the same gene + */ + dataKey: string; + + /** + * view to access the data + */ + view: string; + + /** + * database to access the data + */ + database: string; + + /** + * label of this column for display to the user by default the column name + */ + label: string; + + /** + * column type + */ + type: AttributeType; + + /** + * the categories in case of type=categorical + */ + categories?: string[]; + + /** + * the minimal value in case of type=number + */ + min?: number; + + /** + * the maxmial value in case of type=number + */ + max?: number; + + /** + * wether the attribute is best shown on a log scale + */ + preferLog: boolean; + + getData(cohortDbId: number, filters?: IAllFilters): Promise; // IRow has _id but IScoreRow has not + + getHist(dbId: number, filters?: IAllFilters, bins?: number): Promise<{ bin: string; count: number }[]>; + + getHistWithStorage( + histType: HistRouteType, + params: ICohortDBHistDataParms | ICohortDBHistScoreParms | ICohortDBHistScoreDepletionParms | ICohortDBHistPanelParms, + ): Promise<{ bin: string; count: number }[]>; + + getCount(cohortDbId: number, filters?: IAllFilters): Promise; + + filter(cht: ICohort, filter: INumRange[] | IEqualsList): Promise; + + toJSON(); +} diff --git a/src/data/ISpecialAttribute.ts b/src/data/ISpecialAttribute.ts new file mode 100644 index 0000000..cd99076 --- /dev/null +++ b/src/data/ISpecialAttribute.ts @@ -0,0 +1,53 @@ +import { IAllFilters } from 'tdp_core'; +import { + HistRouteType, + ICohortDBHistDataParms, + ICohortDBHistScoreParms, + ICohortDBHistScoreDepletionParms, + ICohortDBHistPanelParms, + ICohort, + INumRange, + IEqualsList, +} from '../index'; +import { AttributeType, IdValuePair } from './IAttribute'; + +export interface ISpecialAttribute { + readonly overrideSearchBarDetails: boolean; + readonly overrideGetData: boolean; + readonly overrideGetHist: boolean; + readonly overrideGetCount: boolean; + readonly overrideFilter: boolean; + + /** + * id database access the data + */ + readonly id: string; + + label: string; + type: AttributeType; + dataKey: string; + /** + * Possible options the attribute could be formated + */ + options: { id: string; name: string }[]; + + /** + * Option that is should be used to format the data + */ + attributeOption: string; + + getDetailForSearchBar(): HTMLDivElement; + + getData(cohortDbId: number, filters?: IAllFilters): Promise; // IRow has _id but IScoreRow has not + + getHist(dbId: number, filters?: IAllFilters, bins?: number): Promise<{ bin: string; count: number }[]>; + + getHistWithStorage( + histType: HistRouteType, + params: ICohortDBHistDataParms | ICohortDBHistScoreParms | ICohortDBHistScoreDepletionParms | ICohortDBHistPanelParms, + ): Promise<{ bin: string; count: number }[]>; + + getCount(cohortDbId: number, filters?: IAllFilters): Promise; + + filter(cht: ICohort, filter: INumRange[] | IEqualsList, label: string): Promise; +} diff --git a/src/data/SpecialAttribute.ts b/src/data/SpecialAttribute.ts index 4d6233b..5312dce 100644 --- a/src/data/SpecialAttribute.ts +++ b/src/data/SpecialAttribute.ts @@ -1,61 +1,14 @@ import _ from 'lodash'; import { IAllFilters } from 'tdp_core'; -import { Cohort, createCohortWithTreatmentFilter } from '../Cohort'; -import { getRootCohort } from '../cohortview'; -import { - getCohortData, - HistRouteType, - ICohortDBHistDataParms, - ICohortDBHistPanelParms, - ICohortDBHistScoreDepletionParms, - ICohortDBHistScoreParms, - IEqualsList, - INumRange, -} from '../rest'; +import { getCohortData, ICohortDBHistDataParms, ICohortDBHistPanelParms, ICohortDBHistScoreDepletionParms, ICohortDBHistScoreParms } from '../base/rest'; import { deepCopy, getSessionStorageItem, log, setSessionStorageItem } from '../util'; -import { niceName } from '../utilLabels'; -import { AttributeType, IdValuePair } from './Attribute'; - -export interface ISpecialAttribute { - readonly overrideSearchBarDetails: boolean; - readonly overrideGetData: boolean; - readonly overrideGetHist: boolean; - readonly overrideGetCount: boolean; - readonly overrideFilter: boolean; - - /** - * id database access the data - */ - readonly id: string; - - label: string; - type: AttributeType; - dataKey: string; - /** - * Possible options the attribute could be formated - */ - options: { id: string; name: string }[]; - - /** - * Option that is should be used to format the data - */ - attributeOption: string; - - getDetailForSearchBar(): HTMLDivElement; - - getData(cohortDbId: number, filters?: IAllFilters): Promise; // IRow has _id but IScoreRow has not - - getHist(dbId: number, filters?: IAllFilters, bins?: number): Promise<{ bin: string; count: number }[]>; - - getHistWithStorage( - histType: HistRouteType, - params: ICohortDBHistDataParms | ICohortDBHistScoreParms | ICohortDBHistScoreDepletionParms | ICohortDBHistPanelParms, - ): Promise<{ bin: string; count: number }[]>; - - getCount(cohortDbId: number, filters?: IAllFilters): Promise; - - filter(cht: Cohort, filter: INumRange[] | IEqualsList, label: string): Promise; -} +import { niceName } from '../utils/labels'; +import { ICohort } from '../app/interfaces'; +import { createCohortWithTreatmentFilter } from '../Cohort'; +import { CohortContext } from '../CohortContext'; +import { INumRange, IEqualsList, HistRouteType } from '../base'; +import { AttributeType, IdValuePair } from './IAttribute'; +import type { ISpecialAttribute } from './ISpecialAttribute'; export class SATreatment implements ISpecialAttribute { readonly overrideSearchBarDetails: boolean = true; @@ -120,7 +73,7 @@ export class SATreatment implements ISpecialAttribute { // check if histogram was saved in sesison storage if (maxRegimen === null || getSessionStorageItem('treatment#categoriesHist') === null || getSessionStorageItem('treatment#categoriesBaseHist') === null) { let calcMaxRegimen = 0; - const rootCohort = getRootCohort(); + const rootCohort = CohortContext.referenceCohort; const rows = await getCohortData({ cohortId: rootCohort.dbId, attribute: this.id }); // const maxRegimenNumbRows = Math.max(...rows.map((r) => r.treatment).map((t) => t.REGIMEN_NUMBER)); @@ -367,7 +320,7 @@ export class SATreatment implements ISpecialAttribute { throw new Error('Method not implemented.'); } - filter(cht: Cohort, filter: INumRange[] | IEqualsList, label: string): Promise { + filter(cht: ICohort, filter: INumRange[] | IEqualsList, label: string): Promise { log.debug('FILTER of special attribute: ', { cht, filter }); const optName = this.options.filter((o) => o.id === this.attributeOption)[0].name; const baseAgent = this.attributeOption.includes('base'); @@ -385,10 +338,11 @@ export class SATreatment implements ISpecialAttribute { return createCohortWithTreatmentFilter(cht, niceName(`${this.id}:${optName}`), label, baseAgent, agent, rgNumb); } } + return null; } } -const specAttributes: { id: string; getClass: Function }[] = [ +const specAttributes: { id: string; getClass: () => ISpecialAttribute }[] = [ { id: SATreatment.ID, getClass: (): ISpecialAttribute => { diff --git a/src/data/index.ts b/src/data/index.ts index d800a15..3dfdeee 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -1 +1,2 @@ export * from './Attribute'; +export * from './IAttribute'; diff --git a/src/index.ts b/src/index.ts index 59e3491..33d575a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,12 +1,12 @@ +export * from './app'; export * from './data'; export * from './Overview'; export * from './Taskview'; -export * from './app'; export * from './Cohort'; -export * from './CohortInterfaces'; export * from './CohortRepresentations'; export * from './cohortview'; -export * from './rest'; +export * from './base'; export * from './util'; +export * from './utils'; diff --git a/src/phovea.ts b/src/phovea.ts index c0f565f..cb8926d 100644 --- a/src/phovea.ts +++ b/src/phovea.ts @@ -3,12 +3,12 @@ * Copyright (c) The Caleydo Team. All rights reserved. * Licensed under the new BSD license, available at http://caleydo.org/license **************************************************************************** */ -import { IRegistry } from 'tdp_core'; +import type { IRegistry } from 'visyn_core/plugin'; export default function (registry: IRegistry) { // helper functions copied from tdp_core: // ------------------------------------------------------------------------------------------------------- - function actionFunction(id: string, factory: string, loader: () => any, options?: {}) { + function actionFunction(id: string, factory: string, loader: () => unknown, options?: object) { registry.push('actionFunction', id, loader, { factory, ...options }); } diff --git a/src/phovea_registry.ts b/src/phovea_registry.ts index 9a11b28..f702669 100644 --- a/src/phovea_registry.ts +++ b/src/phovea_registry.ts @@ -4,13 +4,14 @@ * Licensed under the new BSD license, available at http://caleydo.org/license **************************************************************************** */ -import { PluginRegistry } from 'tdp_core'; +import { PluginRegistry } from 'visyn_core/plugin'; import reg from './phovea'; /** * build a registry by registering all phovea modules */ // other modules +import 'visyn_core/phovea_registry'; import 'tdp_core/dist/phovea_registry'; // self diff --git a/src/util.ts b/src/util.ts index 73fc7d9..72b22d8 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,9 +1,17 @@ -import {select, Selection} from 'd3v7'; +import { select, Selection } from 'd3v7'; import * as logger from 'loglevel'; -import { NotificationHandler } from 'tdp_core'; -import { ICohort } from './CohortInterfaces'; -import { IAttribute } from './data/Attribute'; -import { IEqualsList, INumRange } from './rest'; +import { IAllFilters, IParams, NotificationHandler } from 'tdp_core'; +import { ICohort } from './app/interfaces'; +import { INumRange, IEqualsList } from './base/interfaces'; +import type { IAttribute } from './data/IAttribute'; + +enum FilterType { + normal, + lt, + lte, + gt, + gte, +} logger.setDefaultLevel(logger.levels.INFO); export const log = logger; @@ -32,7 +40,8 @@ export const deepCopy = (target: T): T => { }); return cp.map((n: any) => deepCopy(n)) as any; } - if (typeof target === 'object' && target !== {}) { + // not empty object + if (typeof target === 'object' && Object.keys(target).length > 0) { const cp = { ...(target as { [key: string]: any }) } as { [key: string]: any }; Object.keys(cp).forEach((k) => { cp[k] = deepCopy(cp[k]); @@ -60,48 +69,6 @@ export function handleDataSaveError(e): void { NotificationHandler.pushNotification('error', msg, 4000); } -export class ScrollLinker { - isSyncingScrollA: boolean; - - isSyncingScrollB: boolean; - - constructor(private divA: HTMLDivElement, private divB: HTMLDivElement, private enabled = true) { - divA.addEventListener('scroll', (e) => this.handleScrollA(e)); - divB.addEventListener('scroll', (e) => this.handleScrollB(e)); - } - - private handleScrollA(e: Event) { - if (!this.isSyncingScrollA && this.enabled) { - this.isSyncingScrollB = true; - this.divB.scrollTop = (e.target as HTMLDivElement).scrollTop; - } - this.isSyncingScrollA = false; - } - - private handleScrollB(e: Event) { - if (!this.isSyncingScrollB && this.enabled) { - this.isSyncingScrollA = true; - this.divA.scrollTop = (e.target as HTMLDivElement).scrollTop; - } - this.isSyncingScrollB = false; - } - - public enable() { - this.enabled = true; - this.divB.scrollTop = this.divA.scrollTop; // sync position - } - - public disable() { - this.enabled = false; - } - - public destroy() { - this.divA.removeEventListener('scroll', (e) => this.handleScrollA(e)); - this.divA.removeEventListener('scroll', (e) => this.handleScrollA(e)); - this.divB.addEventListener('scroll', (e) => this.handleScrollB(e)); - } -} - /** * Returns true if removed, false if it didn't contain the element * @param array array to remove from @@ -170,129 +137,6 @@ export function getAnimatedLoadingBars(): HTMLDivElement { return loadingContainer; } -const category20 = [ - // Based on Category20: https://vega.github.io/vega/docs/schemes/#category20 - // Saturated - '#1f77b4', - '#2ca02c', - '#d62728', - '#9467bd', - '#8c564b', - '#e377c2', - '#7f7f7f', - '#bcbd22', - // unsaturated - '#aec7e8', - '#98df8a', - '#ff9896', - '#c5b0d5', - '#c49c94', - '#f7b6d2', - '#c7c7c7', - '#dbdb8d', -]; - -const tableau20 = [ - // Based on Tableau20: https://vega.github.io/vega/docs/schemes/#tableau20 - // Saturated - '#4c78a8', - '#54a24b', - '#e45756', - '#79706e', - '#d67195', - '#b279a2', - '#9e765f', - // unsaturated - '#9ecae9', - '#88d27a', - '#ff9d98', - '#bab0ac', - '#fcbfd2', - '#d6a5c9', - '#d8b5a5', -]; - -const pastel1 = [ - // based on patel1: https://vega.github.io/vega/docs/schemes/#pastel1 - '#fbb4ae' /* p1:red */, - '#b3cde3' /* p1:blue */, - '#ccebc5' /* p1:green */, - '#decbe4' /* p1:lila */, - '#fed9a6' /* p1:orange */, - '#ffffcc' /* p1:yellow */, - '#e5d8bd' /* p1:brown */, - '#fddaec' /* p1:pink */, - '#f2f2f2' /* p1:grey */, -]; - -const pastel2 = [ - // based on pastel2: https://vega.github.io/vega/docs/schemes/#pastel2 - '#b3e2cd' /* p2:dark green */, - '#fdcdac' /* p2:orange */, - '#cbd5e8' /* p2:blue */, - '#f4cae4' /* p2:pink */, - '#e6f5c9' /* p2:light green */, - '#fff2ae' /* p2:yellow */, - '#f1e2cc' /* p2:brown */, - '#cccccc' /* p2:grey */, -]; - -const set2 = [ - // based on set3: https://vega.github.io/vega/docs/schemes/#set2 - // -> rearranged and without turquose, and grey - '#fc8d62' /* red */, - '#8da0cb' /* blue */, - '#e78ac3' /* pink */, - '#a6d854' /* green */, - '#ffd92f' /* yellow */, - '#e5c494' /* brown */, - // '#66c2a5' /* turquose */, - // '#b3b3b3' /* grey*/, -]; - -const set3 = [ - // based on set3: https://vega.github.io/vega/docs/schemes/#set3 - // -> rearranged and without orange, turquose, and grey - '#8dd3c7' /* set3:turquose */, - '#fdb462' /* set3:orange */, - '#b3de69' /* set3:green */, - '#fb8072' /* set3:red */, - '#ffed6f' /* set3:yellow */, - '#bc80bd' /* set3:lila */, - '#80b1d3' /* set3:blue */, - '#fccde5' /* set3:pink */, - '#ccebc5' /* set3:mint */, - '#bebada' /* set3:light lila */, - '#d8b5a5' /* t20: light brown */, - // '#ffffb3' /* set3:light yellow */, - // '#d9d9d9' /* set3:grey */, -]; - -const combination = [ - // combination of different set: set3, tableau20, pastel1 & 2 - '#80b1d3' /* set3:blue */, - '#fb8072' /* set3:red */, - '#b3de69' /* set3:green */, - '#bc80bd' /* set3:lila */, - '#ffed6f' /* set3:yellow */, - '#fcbfd2' /* t20:light pink */, - '#d8b5a5' /* t20: light brown */, - '#e6f5c9' /* p2:light green */, - '#decbe4' /* p1:lila */, - '#ffffb3' /* set3:light yellow */, - '#fddaec' /* p1:pink */, - '#f1e2cc' /* p2:brown */, -]; - -export class CohortColorSchema { - static readonly COLOR_SCHEME = set3; - - static get(index: number): string { - const moduloIndex = index % CohortColorSchema.COLOR_SCHEME.length; - return CohortColorSchema.COLOR_SCHEME[moduloIndex]; - } -} - export function setSessionStorageItem(key: string, value: any) { const strValue = JSON.stringify(value); sessionStorage.setItem(key, strValue); @@ -335,6 +179,91 @@ export class DebugTools { */ static async sleep(millis: number): Promise { log.info('taking a little nap'); - return new Promise((resolve) => setTimeout(resolve, millis)); + return new Promise((resolve) => { + setTimeout(resolve, millis); + }); + } +} + +function mergerAllFilterPart(filterType: FilterType, existingFilter: IParams, newFilter: IParams): IParams { + let mergedFilter = deepCopy(existingFilter); + // const currType : FilterType = FilterType.normal; + let filterContradiction = false; + // go through all attribuets of the new filter + for (const attr in newFilter) { + // check if attribute exists in the new filter + if (Object.prototype.hasOwnProperty.call(newFilter, attr)) { + // check if attribute exists in the existing filter + if (Object.prototype.hasOwnProperty.call(existingFilter, attr)) { + const newVal = newFilter[attr]; // current value for attribute + const existVal = existingFilter[attr]; // current value for attribute + + if (filterType === FilterType.normal) { + // convert newVal to an array of values + const newValArray = Array.isArray(newVal) ? (newVal as string[] | number[] | boolean[]) : new Array(newVal as string | number | boolean); + // convert existVal to an array of values + const existValArray = Array.isArray(existVal) ? (existVal as string[] | number[] | boolean[]) : new Array(existVal as string | number | boolean); + // if all new values are part of the existing values, then the filter is OK + for (const nv of newValArray) { + if (!existValArray.includes(nv)) { + filterContradiction = true; + } + } + // no filter contradiction -> new filter values can be used + if (!filterContradiction) { + // outside of for-loop + mergedFilter[attr] = newFilter[attr]; + } + } else if (filterType === FilterType.lt || filterType === FilterType.lte) { + // smaller is OK + if (newVal <= existVal) { + mergedFilter[attr] = newFilter[attr]; + } else { + filterContradiction = true; + } + } else if (filterType === FilterType.gt || filterType === FilterType.gte) { + // bigger is OK + if (newVal >= existVal) { + mergedFilter[attr] = newFilter[attr]; + } else { + filterContradiction = true; + } + } + } else { + // the new filter attribute is not existing -> add to the resulting filter + mergedFilter[attr] = newFilter[attr]; + } + } + } + + if (filterContradiction) { + mergedFilter = null; } + log.debug('Filter Contradiction: ', filterContradiction); + return mergedFilter; +} + +export function mergeTwoAllFilters(existingFilter: IAllFilters, newFilter: IAllFilters): IAllFilters { + let mergerAllFilter: IAllFilters = null; + if (existingFilter !== null) { + const normal: IParams = mergerAllFilterPart(FilterType.normal, existingFilter.normal, newFilter.normal); + const lt: IParams = mergerAllFilterPart(FilterType.lt, existingFilter.lt, newFilter.lt); + const lte: IParams = mergerAllFilterPart(FilterType.lte, existingFilter.lte, newFilter.lte); + const gt: IParams = mergerAllFilterPart(FilterType.gt, existingFilter.gt, newFilter.gt); + const gte: IParams = mergerAllFilterPart(FilterType.gte, existingFilter.gte, newFilter.gte); + + // if the filters are all !== null, that means there is no filter contradiction -> set all filters of mergerAllFilter + // otherwise the mergerAllFilter stays null + if (normal !== null && lte !== null && lte !== null && gt !== null && gte !== null) { + mergerAllFilter = { + normal, + lt, + lte, + gt, + gte, + }; + } + } + + return mergerAllFilter; } diff --git a/src/utils/RouterScrollToTop.tsx b/src/utils/RouterScrollToTop.tsx new file mode 100644 index 0000000..a698651 --- /dev/null +++ b/src/utils/RouterScrollToTop.tsx @@ -0,0 +1,16 @@ +import { useEffect } from 'react'; +import { useLocation } from 'react-router-dom'; + +/** + * Scroll the window up on every navigation + * @see https://reactrouter.com/web/guides/scroll-restoration + */ +export function RouterScrollToTop() { + const { pathname } = useLocation(); + + useEffect(() => { + window.scrollTo(0, 0); + }, [pathname]); + + return null; +} diff --git a/src/utils/ScrollLinker.ts b/src/utils/ScrollLinker.ts new file mode 100644 index 0000000..16a0962 --- /dev/null +++ b/src/utils/ScrollLinker.ts @@ -0,0 +1,41 @@ +export class ScrollLinker { + isSyncingScrollA: boolean; + + isSyncingScrollB: boolean; + + constructor(private divA: HTMLDivElement, private divB: HTMLDivElement, private enabled = true) { + divA.addEventListener('scroll', (e) => this.handleScrollA(e)); + divB.addEventListener('scroll', (e) => this.handleScrollB(e)); + } + + private handleScrollA(e: Event) { + if (!this.isSyncingScrollA && this.enabled) { + this.isSyncingScrollB = true; + this.divB.scrollTop = (e.target as HTMLDivElement).scrollTop; + } + this.isSyncingScrollA = false; + } + + private handleScrollB(e: Event) { + if (!this.isSyncingScrollB && this.enabled) { + this.isSyncingScrollA = true; + this.divA.scrollTop = (e.target as HTMLDivElement).scrollTop; + } + this.isSyncingScrollB = false; + } + + public enable() { + this.enabled = true; + this.divB.scrollTop = this.divA.scrollTop; // sync position + } + + public disable() { + this.enabled = false; + } + + public destroy() { + this.divA.removeEventListener('scroll', (e) => this.handleScrollA(e)); + this.divA.removeEventListener('scroll', (e) => this.handleScrollA(e)); + this.divB.addEventListener('scroll', (e) => this.handleScrollB(e)); + } +} diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..8ce3f7c --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1 @@ +export * from './RouterScrollToTop'; diff --git a/src/utilLabels.ts b/src/utils/labels.ts similarity index 94% rename from src/utilLabels.ts rename to src/utils/labels.ts index 85229d2..7ed7c4d 100644 --- a/src/utilLabels.ts +++ b/src/utils/labels.ts @@ -1,5 +1,5 @@ -import {format} from 'd3v7'; -import {IEqualsList, INumRange, isEqualsList, isNumRangeFilter, NumRangeOperators} from './rest'; +import { format } from 'd3v7'; +import { INumRange, IEqualsList, isNumRangeFilter, isEqualsList, NumRangeOperators } from '../base'; export function niceName(label: string): string { return label @@ -8,14 +8,42 @@ export function niceName(label: string): string { .join(' '); } -export function easyLabelFromFilterArray(filter: INumRange[] | IEqualsList, attrLabel: string = null): string { - let label = ''; - if (Array.isArray(filter)) { - label = filter.map((a) => easyLabelFromFilter(a, attrLabel)).join(' / '); - } else { - label = easyLabelFromFilter(filter, attrLabel); +// TODO label +// export function labelFromRanges(lowerOperator: '(' | '[', lowerBound: number, upperBound: number, upperOperator: ')' | ']', attr: IAttribute): string { +export function labelFromRanges(lowerOperator: '(' | '[', lowerBound: number, upperBound: number, upperOperator: ')' | ']', attrLabel: string): string { + // const attribute = attr && attr.label ? attr.label : 'x'; + const attribute = attrLabel || 'x'; + const htmlLte = '≤'; + const htmlLt = '<'; + const htmlGte = '≥'; + const htmlGt = '>'; + const formatter = format('.4~f'); + + if (lowerOperator === null) { + // const up = upperOperator === ')' ? htmlLt : htmlLte; + // return `${attribute} ${up} ${formatter(upperBound as number)}`; + const up = upperOperator === ')' ? htmlLt : htmlLte; + return `${up} ${formatter(upperBound as number)}`; } - return label; + if (upperOperator === null) { + // const low = lowerOperator === '(' ? htmlLt : htmlLte; + // return `${formatter(lowerBound as number)} ${low} ${attribute}`; + const low = lowerOperator === '(' ? htmlGt : htmlGte; + return `${low} ${formatter(lowerBound as number)}`; + } + if (formatter(lowerBound) === formatter(upperBound)) { + return `${formatter(lowerBound)}`; + } + // const low = lowerOperator === '(' ? htmlLt : htmlLte; + // const up = upperOperator === ')' ? htmlLt : htmlLte; + // return `${formatter(lowerBound as number)} ${low} ${attribute} ${up} ${formatter(upperBound as number)}`; + const low = lowerOperator === '(' ? htmlGt : htmlGte; + const up = upperOperator === ')' ? htmlLt : htmlLte; + return ` ${low} ${formatter(lowerBound as number)} to ${up} ${formatter(upperBound as number)}`; +} + +export function labelForCategories(categories: Array): string { + return categories.map((cat) => niceName(`${cat}`)).join('/'); } export function easyLabelFromFilter(filter: INumRange | IEqualsList, attrLabel: string = null): string { @@ -37,6 +65,16 @@ export function easyLabelFromFilter(filter: INumRange | IEqualsList, attrLabel: throw new Error('not implemented ☠'); } +export function easyLabelFromFilterArray(filter: INumRange[] | IEqualsList, attrLabel: string = null): string { + let label = ''; + if (Array.isArray(filter)) { + label = filter.map((a) => easyLabelFromFilter(a, attrLabel)).join(' / '); + } else { + label = easyLabelFromFilter(filter, attrLabel); + } + return label; +} + // ----- // export function labelFromFilterArray(filter: INumRange[] | IEqualsList, attr: IAttribute): string { @@ -74,44 +112,6 @@ export function labelFromFilter(filter: INumRange | IEqualsList, attrLabel: stri throw new Error('not implemented ☠'); } -// TODO label -// export function labelFromRanges(lowerOperator: '(' | '[', lowerBound: number, upperBound: number, upperOperator: ')' | ']', attr: IAttribute): string { -export function labelFromRanges(lowerOperator: '(' | '[', lowerBound: number, upperBound: number, upperOperator: ')' | ']', attrLabel: string): string { - // const attribute = attr && attr.label ? attr.label : 'x'; - const attribute = attrLabel || 'x'; - const htmlLte = '≤'; - const htmlLt = '<'; - const htmlGte = '≥'; - const htmlGt = '>'; - const formatter = format('.4~f'); - - if (lowerOperator === null) { - // const up = upperOperator === ')' ? htmlLt : htmlLte; - // return `${attribute} ${up} ${formatter(upperBound as number)}`; - const up = upperOperator === ')' ? htmlLt : htmlLte; - return `${up} ${formatter(upperBound as number)}`; - } - if (upperOperator === null) { - // const low = lowerOperator === '(' ? htmlLt : htmlLte; - // return `${formatter(lowerBound as number)} ${low} ${attribute}`; - const low = lowerOperator === '(' ? htmlGt : htmlGte; - return `${low} ${formatter(lowerBound as number)}`; - } - if (formatter(lowerBound) === formatter(upperBound)) { - return `${formatter(lowerBound)}`; - } - // const low = lowerOperator === '(' ? htmlLt : htmlLte; - // const up = upperOperator === ')' ? htmlLt : htmlLte; - // return `${formatter(lowerBound as number)} ${low} ${attribute} ${up} ${formatter(upperBound as number)}`; - const low = lowerOperator === '(' ? htmlGt : htmlGte; - const up = upperOperator === ')' ? htmlLt : htmlLte; - return ` ${low} ${formatter(lowerBound as number)} to ${up} ${formatter(upperBound as number)}`; -} - -export function labelForCategories(categories: Array): string { - return categories.map((cat) => niceName(`${cat}`)).join('/'); -} - // plural and sigular functions from: https://stackoverflow.com/a/57129703 // licensed under CC-BY-SA 4.0, see https://stackoverflow.com/help/licensing /** @@ -126,7 +126,7 @@ export function plural(word: string, amount?: number): string { if (amount !== undefined && amount === 1) { return word; } - const plural: { [key: string]: string } = { + const pluralWords: { [key: string]: string } = { '(quiz)$': '$1zes', '^(ox)$': '$1en', '([m|l])ouse$': '$1ice', @@ -201,11 +201,11 @@ export function plural(word: string, amount?: number): string { } } // check for matches using regular expressions - for (const reg in plural) { - if (plural.hasOwnProperty(reg)) { + for (const reg in pluralWords) { + if (pluralWords.hasOwnProperty(reg)) { const pattern = new RegExp(reg, 'i'); if (pattern.test(word)) { - return word.replace(pattern, plural[reg]); + return word.replace(pattern, pluralWords[reg]); } } } @@ -224,7 +224,7 @@ export function singular(word: string, amount?: number): string { if (amount !== undefined && amount !== 1) { return word; } - const singular: { [key: string]: string } = { + const singularWords: { [key: string]: string } = { '(quiz)zes$': '$1', '(matr)ices$': '$1ix', '(vert|ind)ices$': '$1ex', @@ -309,11 +309,11 @@ export function singular(word: string, amount?: number): string { } } // check for matches using regular expressions - for (const reg in singular) { - if (singular.hasOwnProperty(reg)) { + for (const reg in singularWords) { + if (singularWords.hasOwnProperty(reg)) { const pattern = new RegExp(reg, 'i'); if (pattern.test(word)) { - return word.replace(pattern, singular[reg]); + return word.replace(pattern, singularWords[reg]); } } } diff --git a/tsconfig.json b/tsconfig.json index 213cc4d..b5b1dcb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,6 +2,7 @@ "extends": "visyn_scripts/config/tsconfig.template.json", "compilerOptions": { "outDir": "./dist", + "sourceMap": false, }, "include": [ "src/**/*.ts",