1*9880d681SAndroid Build Coastguard Worker //===- SourceCoverageView.h - Code coverage view for source code ----------===// 2*9880d681SAndroid Build Coastguard Worker // 3*9880d681SAndroid Build Coastguard Worker // The LLVM Compiler Infrastructure 4*9880d681SAndroid Build Coastguard Worker // 5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source 6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details. 7*9880d681SAndroid Build Coastguard Worker // 8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 9*9880d681SAndroid Build Coastguard Worker /// 10*9880d681SAndroid Build Coastguard Worker /// \file This class implements rendering for code coverage of source code. 11*9880d681SAndroid Build Coastguard Worker /// 12*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 13*9880d681SAndroid Build Coastguard Worker 14*9880d681SAndroid Build Coastguard Worker #ifndef LLVM_COV_SOURCECOVERAGEVIEW_H 15*9880d681SAndroid Build Coastguard Worker #define LLVM_COV_SOURCECOVERAGEVIEW_H 16*9880d681SAndroid Build Coastguard Worker 17*9880d681SAndroid Build Coastguard Worker #include "CoverageViewOptions.h" 18*9880d681SAndroid Build Coastguard Worker #include "llvm/ProfileData/Coverage/CoverageMapping.h" 19*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/MemoryBuffer.h" 20*9880d681SAndroid Build Coastguard Worker #include <vector> 21*9880d681SAndroid Build Coastguard Worker 22*9880d681SAndroid Build Coastguard Worker namespace llvm { 23*9880d681SAndroid Build Coastguard Worker 24*9880d681SAndroid Build Coastguard Worker class SourceCoverageView; 25*9880d681SAndroid Build Coastguard Worker 26*9880d681SAndroid Build Coastguard Worker /// \brief A view that represents a macro or include expansion. 27*9880d681SAndroid Build Coastguard Worker struct ExpansionView { 28*9880d681SAndroid Build Coastguard Worker coverage::CounterMappingRegion Region; 29*9880d681SAndroid Build Coastguard Worker std::unique_ptr<SourceCoverageView> View; 30*9880d681SAndroid Build Coastguard Worker ExpansionViewExpansionView31*9880d681SAndroid Build Coastguard Worker ExpansionView(const coverage::CounterMappingRegion &Region, 32*9880d681SAndroid Build Coastguard Worker std::unique_ptr<SourceCoverageView> View) 33*9880d681SAndroid Build Coastguard Worker : Region(Region), View(std::move(View)) {} ExpansionViewExpansionView34*9880d681SAndroid Build Coastguard Worker ExpansionView(ExpansionView &&RHS) 35*9880d681SAndroid Build Coastguard Worker : Region(std::move(RHS.Region)), View(std::move(RHS.View)) {} 36*9880d681SAndroid Build Coastguard Worker ExpansionView &operator=(ExpansionView &&RHS) { 37*9880d681SAndroid Build Coastguard Worker Region = std::move(RHS.Region); 38*9880d681SAndroid Build Coastguard Worker View = std::move(RHS.View); 39*9880d681SAndroid Build Coastguard Worker return *this; 40*9880d681SAndroid Build Coastguard Worker } 41*9880d681SAndroid Build Coastguard Worker getLineExpansionView42*9880d681SAndroid Build Coastguard Worker unsigned getLine() const { return Region.LineStart; } getStartColExpansionView43*9880d681SAndroid Build Coastguard Worker unsigned getStartCol() const { return Region.ColumnStart; } getEndColExpansionView44*9880d681SAndroid Build Coastguard Worker unsigned getEndCol() const { return Region.ColumnEnd; } 45*9880d681SAndroid Build Coastguard Worker 46*9880d681SAndroid Build Coastguard Worker friend bool operator<(const ExpansionView &LHS, const ExpansionView &RHS) { 47*9880d681SAndroid Build Coastguard Worker return LHS.Region.startLoc() < RHS.Region.startLoc(); 48*9880d681SAndroid Build Coastguard Worker } 49*9880d681SAndroid Build Coastguard Worker }; 50*9880d681SAndroid Build Coastguard Worker 51*9880d681SAndroid Build Coastguard Worker /// \brief A view that represents a function instantiation. 52*9880d681SAndroid Build Coastguard Worker struct InstantiationView { 53*9880d681SAndroid Build Coastguard Worker StringRef FunctionName; 54*9880d681SAndroid Build Coastguard Worker unsigned Line; 55*9880d681SAndroid Build Coastguard Worker std::unique_ptr<SourceCoverageView> View; 56*9880d681SAndroid Build Coastguard Worker InstantiationViewInstantiationView57*9880d681SAndroid Build Coastguard Worker InstantiationView(StringRef FunctionName, unsigned Line, 58*9880d681SAndroid Build Coastguard Worker std::unique_ptr<SourceCoverageView> View) 59*9880d681SAndroid Build Coastguard Worker : FunctionName(FunctionName), Line(Line), View(std::move(View)) {} InstantiationViewInstantiationView60*9880d681SAndroid Build Coastguard Worker InstantiationView(InstantiationView &&RHS) 61*9880d681SAndroid Build Coastguard Worker : FunctionName(std::move(RHS.FunctionName)), Line(std::move(RHS.Line)), 62*9880d681SAndroid Build Coastguard Worker View(std::move(RHS.View)) {} 63*9880d681SAndroid Build Coastguard Worker InstantiationView &operator=(InstantiationView &&RHS) { 64*9880d681SAndroid Build Coastguard Worker FunctionName = std::move(RHS.FunctionName); 65*9880d681SAndroid Build Coastguard Worker Line = std::move(RHS.Line); 66*9880d681SAndroid Build Coastguard Worker View = std::move(RHS.View); 67*9880d681SAndroid Build Coastguard Worker return *this; 68*9880d681SAndroid Build Coastguard Worker } 69*9880d681SAndroid Build Coastguard Worker 70*9880d681SAndroid Build Coastguard Worker friend bool operator<(const InstantiationView &LHS, 71*9880d681SAndroid Build Coastguard Worker const InstantiationView &RHS) { 72*9880d681SAndroid Build Coastguard Worker return LHS.Line < RHS.Line; 73*9880d681SAndroid Build Coastguard Worker } 74*9880d681SAndroid Build Coastguard Worker }; 75*9880d681SAndroid Build Coastguard Worker 76*9880d681SAndroid Build Coastguard Worker /// \brief Coverage statistics for a single line. 77*9880d681SAndroid Build Coastguard Worker struct LineCoverageStats { 78*9880d681SAndroid Build Coastguard Worker uint64_t ExecutionCount; 79*9880d681SAndroid Build Coastguard Worker unsigned RegionCount; 80*9880d681SAndroid Build Coastguard Worker bool Mapped; 81*9880d681SAndroid Build Coastguard Worker LineCoverageStatsLineCoverageStats82*9880d681SAndroid Build Coastguard Worker LineCoverageStats() : ExecutionCount(0), RegionCount(0), Mapped(false) {} 83*9880d681SAndroid Build Coastguard Worker isMappedLineCoverageStats84*9880d681SAndroid Build Coastguard Worker bool isMapped() const { return Mapped; } 85*9880d681SAndroid Build Coastguard Worker hasMultipleRegionsLineCoverageStats86*9880d681SAndroid Build Coastguard Worker bool hasMultipleRegions() const { return RegionCount > 1; } 87*9880d681SAndroid Build Coastguard Worker addRegionStartCountLineCoverageStats88*9880d681SAndroid Build Coastguard Worker void addRegionStartCount(uint64_t Count) { 89*9880d681SAndroid Build Coastguard Worker // The max of all region starts is the most interesting value. 90*9880d681SAndroid Build Coastguard Worker addRegionCount(RegionCount ? std::max(ExecutionCount, Count) : Count); 91*9880d681SAndroid Build Coastguard Worker ++RegionCount; 92*9880d681SAndroid Build Coastguard Worker } 93*9880d681SAndroid Build Coastguard Worker addRegionCountLineCoverageStats94*9880d681SAndroid Build Coastguard Worker void addRegionCount(uint64_t Count) { 95*9880d681SAndroid Build Coastguard Worker Mapped = true; 96*9880d681SAndroid Build Coastguard Worker ExecutionCount = Count; 97*9880d681SAndroid Build Coastguard Worker } 98*9880d681SAndroid Build Coastguard Worker }; 99*9880d681SAndroid Build Coastguard Worker 100*9880d681SAndroid Build Coastguard Worker /// \brief A file manager that handles format-aware file creation. 101*9880d681SAndroid Build Coastguard Worker class CoveragePrinter { 102*9880d681SAndroid Build Coastguard Worker const CoverageViewOptions &Opts; 103*9880d681SAndroid Build Coastguard Worker 104*9880d681SAndroid Build Coastguard Worker public: 105*9880d681SAndroid Build Coastguard Worker struct StreamDestructor { 106*9880d681SAndroid Build Coastguard Worker void operator()(raw_ostream *OS) const; 107*9880d681SAndroid Build Coastguard Worker }; 108*9880d681SAndroid Build Coastguard Worker 109*9880d681SAndroid Build Coastguard Worker using OwnedStream = std::unique_ptr<raw_ostream, StreamDestructor>; 110*9880d681SAndroid Build Coastguard Worker 111*9880d681SAndroid Build Coastguard Worker protected: CoveragePrinter(const CoverageViewOptions & Opts)112*9880d681SAndroid Build Coastguard Worker CoveragePrinter(const CoverageViewOptions &Opts) : Opts(Opts) {} 113*9880d681SAndroid Build Coastguard Worker 114*9880d681SAndroid Build Coastguard Worker /// \brief Return `OutputDir/ToplevelDir/Path.Extension`. If \p InToplevel is 115*9880d681SAndroid Build Coastguard Worker /// false, skip the ToplevelDir component. If \p Relative is false, skip the 116*9880d681SAndroid Build Coastguard Worker /// OutputDir component. 117*9880d681SAndroid Build Coastguard Worker std::string getOutputPath(StringRef Path, StringRef Extension, 118*9880d681SAndroid Build Coastguard Worker bool InToplevel, bool Relative = true); 119*9880d681SAndroid Build Coastguard Worker 120*9880d681SAndroid Build Coastguard Worker /// \brief If directory output is enabled, create a file in that directory 121*9880d681SAndroid Build Coastguard Worker /// at the path given by getOutputPath(). Otherwise, return stdout. 122*9880d681SAndroid Build Coastguard Worker Expected<OwnedStream> createOutputStream(StringRef Path, StringRef Extension, 123*9880d681SAndroid Build Coastguard Worker bool InToplevel); 124*9880d681SAndroid Build Coastguard Worker 125*9880d681SAndroid Build Coastguard Worker /// \brief Return the sub-directory name for file coverage reports. getCoverageDir()126*9880d681SAndroid Build Coastguard Worker static StringRef getCoverageDir() { return "coverage"; } 127*9880d681SAndroid Build Coastguard Worker 128*9880d681SAndroid Build Coastguard Worker public: 129*9880d681SAndroid Build Coastguard Worker static std::unique_ptr<CoveragePrinter> 130*9880d681SAndroid Build Coastguard Worker create(const CoverageViewOptions &Opts); 131*9880d681SAndroid Build Coastguard Worker ~CoveragePrinter()132*9880d681SAndroid Build Coastguard Worker virtual ~CoveragePrinter() {} 133*9880d681SAndroid Build Coastguard Worker 134*9880d681SAndroid Build Coastguard Worker /// @name File Creation Interface 135*9880d681SAndroid Build Coastguard Worker /// @{ 136*9880d681SAndroid Build Coastguard Worker 137*9880d681SAndroid Build Coastguard Worker /// \brief Create a file to print a coverage view into. 138*9880d681SAndroid Build Coastguard Worker virtual Expected<OwnedStream> createViewFile(StringRef Path, 139*9880d681SAndroid Build Coastguard Worker bool InToplevel) = 0; 140*9880d681SAndroid Build Coastguard Worker 141*9880d681SAndroid Build Coastguard Worker /// \brief Close a file which has been used to print a coverage view. 142*9880d681SAndroid Build Coastguard Worker virtual void closeViewFile(OwnedStream OS) = 0; 143*9880d681SAndroid Build Coastguard Worker 144*9880d681SAndroid Build Coastguard Worker /// \brief Create an index which lists reports for the given source files. 145*9880d681SAndroid Build Coastguard Worker virtual Error createIndexFile(ArrayRef<StringRef> SourceFiles) = 0; 146*9880d681SAndroid Build Coastguard Worker 147*9880d681SAndroid Build Coastguard Worker /// @} 148*9880d681SAndroid Build Coastguard Worker }; 149*9880d681SAndroid Build Coastguard Worker 150*9880d681SAndroid Build Coastguard Worker /// \brief A code coverage view of a source file or function. 151*9880d681SAndroid Build Coastguard Worker /// 152*9880d681SAndroid Build Coastguard Worker /// A source coverage view and its nested sub-views form a file-oriented 153*9880d681SAndroid Build Coastguard Worker /// representation of code coverage data. This view can be printed out by a 154*9880d681SAndroid Build Coastguard Worker /// renderer which implements the Rendering Interface. 155*9880d681SAndroid Build Coastguard Worker class SourceCoverageView { 156*9880d681SAndroid Build Coastguard Worker /// A function or file name. 157*9880d681SAndroid Build Coastguard Worker StringRef SourceName; 158*9880d681SAndroid Build Coastguard Worker 159*9880d681SAndroid Build Coastguard Worker /// A memory buffer backing the source on display. 160*9880d681SAndroid Build Coastguard Worker const MemoryBuffer &File; 161*9880d681SAndroid Build Coastguard Worker 162*9880d681SAndroid Build Coastguard Worker /// Various options to guide the coverage renderer. 163*9880d681SAndroid Build Coastguard Worker const CoverageViewOptions &Options; 164*9880d681SAndroid Build Coastguard Worker 165*9880d681SAndroid Build Coastguard Worker /// Complete coverage information about the source on display. 166*9880d681SAndroid Build Coastguard Worker coverage::CoverageData CoverageInfo; 167*9880d681SAndroid Build Coastguard Worker 168*9880d681SAndroid Build Coastguard Worker /// A container for all expansions (e.g macros) in the source on display. 169*9880d681SAndroid Build Coastguard Worker std::vector<ExpansionView> ExpansionSubViews; 170*9880d681SAndroid Build Coastguard Worker 171*9880d681SAndroid Build Coastguard Worker /// A container for all instantiations (e.g template functions) in the source 172*9880d681SAndroid Build Coastguard Worker /// on display. 173*9880d681SAndroid Build Coastguard Worker std::vector<InstantiationView> InstantiationSubViews; 174*9880d681SAndroid Build Coastguard Worker 175*9880d681SAndroid Build Coastguard Worker protected: 176*9880d681SAndroid Build Coastguard Worker struct LineRef { 177*9880d681SAndroid Build Coastguard Worker StringRef Line; 178*9880d681SAndroid Build Coastguard Worker int64_t LineNo; 179*9880d681SAndroid Build Coastguard Worker LineRefLineRef180*9880d681SAndroid Build Coastguard Worker LineRef(StringRef Line, int64_t LineNo) : Line(Line), LineNo(LineNo) {} 181*9880d681SAndroid Build Coastguard Worker }; 182*9880d681SAndroid Build Coastguard Worker 183*9880d681SAndroid Build Coastguard Worker using CoverageSegmentArray = ArrayRef<const coverage::CoverageSegment *>; 184*9880d681SAndroid Build Coastguard Worker 185*9880d681SAndroid Build Coastguard Worker /// @name Rendering Interface 186*9880d681SAndroid Build Coastguard Worker /// @{ 187*9880d681SAndroid Build Coastguard Worker 188*9880d681SAndroid Build Coastguard Worker /// \brief Render a header for the view. 189*9880d681SAndroid Build Coastguard Worker virtual void renderViewHeader(raw_ostream &OS) = 0; 190*9880d681SAndroid Build Coastguard Worker 191*9880d681SAndroid Build Coastguard Worker /// \brief Render a footer for the view. 192*9880d681SAndroid Build Coastguard Worker virtual void renderViewFooter(raw_ostream &OS) = 0; 193*9880d681SAndroid Build Coastguard Worker 194*9880d681SAndroid Build Coastguard Worker /// \brief Render the source name for the view. 195*9880d681SAndroid Build Coastguard Worker virtual void renderSourceName(raw_ostream &OS) = 0; 196*9880d681SAndroid Build Coastguard Worker 197*9880d681SAndroid Build Coastguard Worker /// \brief Render the line prefix at the given \p ViewDepth. 198*9880d681SAndroid Build Coastguard Worker virtual void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) = 0; 199*9880d681SAndroid Build Coastguard Worker 200*9880d681SAndroid Build Coastguard Worker /// \brief Render the line suffix at the given \p ViewDepth. 201*9880d681SAndroid Build Coastguard Worker virtual void renderLineSuffix(raw_ostream &OS, unsigned ViewDepth) = 0; 202*9880d681SAndroid Build Coastguard Worker 203*9880d681SAndroid Build Coastguard Worker /// \brief Render a view divider at the given \p ViewDepth. 204*9880d681SAndroid Build Coastguard Worker virtual void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) = 0; 205*9880d681SAndroid Build Coastguard Worker 206*9880d681SAndroid Build Coastguard Worker /// \brief Render a source line with highlighting. 207*9880d681SAndroid Build Coastguard Worker virtual void renderLine(raw_ostream &OS, LineRef L, 208*9880d681SAndroid Build Coastguard Worker const coverage::CoverageSegment *WrappedSegment, 209*9880d681SAndroid Build Coastguard Worker CoverageSegmentArray Segments, unsigned ExpansionCol, 210*9880d681SAndroid Build Coastguard Worker unsigned ViewDepth) = 0; 211*9880d681SAndroid Build Coastguard Worker 212*9880d681SAndroid Build Coastguard Worker /// \brief Render the line's execution count column. 213*9880d681SAndroid Build Coastguard Worker virtual void renderLineCoverageColumn(raw_ostream &OS, 214*9880d681SAndroid Build Coastguard Worker const LineCoverageStats &Line) = 0; 215*9880d681SAndroid Build Coastguard Worker 216*9880d681SAndroid Build Coastguard Worker /// \brief Render the line number column. 217*9880d681SAndroid Build Coastguard Worker virtual void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) = 0; 218*9880d681SAndroid Build Coastguard Worker 219*9880d681SAndroid Build Coastguard Worker /// \brief Render all the region's execution counts on a line. 220*9880d681SAndroid Build Coastguard Worker virtual void renderRegionMarkers(raw_ostream &OS, 221*9880d681SAndroid Build Coastguard Worker CoverageSegmentArray Segments, 222*9880d681SAndroid Build Coastguard Worker unsigned ViewDepth) = 0; 223*9880d681SAndroid Build Coastguard Worker 224*9880d681SAndroid Build Coastguard Worker /// \brief Render the site of an expansion. 225*9880d681SAndroid Build Coastguard Worker virtual void 226*9880d681SAndroid Build Coastguard Worker renderExpansionSite(raw_ostream &OS, LineRef L, 227*9880d681SAndroid Build Coastguard Worker const coverage::CoverageSegment *WrappedSegment, 228*9880d681SAndroid Build Coastguard Worker CoverageSegmentArray Segments, unsigned ExpansionCol, 229*9880d681SAndroid Build Coastguard Worker unsigned ViewDepth) = 0; 230*9880d681SAndroid Build Coastguard Worker 231*9880d681SAndroid Build Coastguard Worker /// \brief Render an expansion view and any nested views. 232*9880d681SAndroid Build Coastguard Worker virtual void renderExpansionView(raw_ostream &OS, ExpansionView &ESV, 233*9880d681SAndroid Build Coastguard Worker unsigned ViewDepth) = 0; 234*9880d681SAndroid Build Coastguard Worker 235*9880d681SAndroid Build Coastguard Worker /// \brief Render an instantiation view and any nested views. 236*9880d681SAndroid Build Coastguard Worker virtual void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV, 237*9880d681SAndroid Build Coastguard Worker unsigned ViewDepth) = 0; 238*9880d681SAndroid Build Coastguard Worker 239*9880d681SAndroid Build Coastguard Worker /// @} 240*9880d681SAndroid Build Coastguard Worker 241*9880d681SAndroid Build Coastguard Worker /// \brief Format a count using engineering notation with 3 significant 242*9880d681SAndroid Build Coastguard Worker /// digits. 243*9880d681SAndroid Build Coastguard Worker static std::string formatCount(uint64_t N); 244*9880d681SAndroid Build Coastguard Worker 245*9880d681SAndroid Build Coastguard Worker /// \brief Check if region marker output is expected for a line. 246*9880d681SAndroid Build Coastguard Worker bool shouldRenderRegionMarkers(bool LineHasMultipleRegions) const; 247*9880d681SAndroid Build Coastguard Worker 248*9880d681SAndroid Build Coastguard Worker /// \brief Check if there are any sub-views attached to this view. 249*9880d681SAndroid Build Coastguard Worker bool hasSubViews() const; 250*9880d681SAndroid Build Coastguard Worker SourceCoverageView(StringRef SourceName,const MemoryBuffer & File,const CoverageViewOptions & Options,coverage::CoverageData && CoverageInfo)251*9880d681SAndroid Build Coastguard Worker SourceCoverageView(StringRef SourceName, const MemoryBuffer &File, 252*9880d681SAndroid Build Coastguard Worker const CoverageViewOptions &Options, 253*9880d681SAndroid Build Coastguard Worker coverage::CoverageData &&CoverageInfo) 254*9880d681SAndroid Build Coastguard Worker : SourceName(SourceName), File(File), Options(Options), 255*9880d681SAndroid Build Coastguard Worker CoverageInfo(std::move(CoverageInfo)) {} 256*9880d681SAndroid Build Coastguard Worker 257*9880d681SAndroid Build Coastguard Worker public: 258*9880d681SAndroid Build Coastguard Worker static std::unique_ptr<SourceCoverageView> 259*9880d681SAndroid Build Coastguard Worker create(StringRef SourceName, const MemoryBuffer &File, 260*9880d681SAndroid Build Coastguard Worker const CoverageViewOptions &Options, 261*9880d681SAndroid Build Coastguard Worker coverage::CoverageData &&CoverageInfo); 262*9880d681SAndroid Build Coastguard Worker ~SourceCoverageView()263*9880d681SAndroid Build Coastguard Worker virtual ~SourceCoverageView() {} 264*9880d681SAndroid Build Coastguard Worker getSourceName()265*9880d681SAndroid Build Coastguard Worker StringRef getSourceName() const { return SourceName; } 266*9880d681SAndroid Build Coastguard Worker getOptions()267*9880d681SAndroid Build Coastguard Worker const CoverageViewOptions &getOptions() const { return Options; } 268*9880d681SAndroid Build Coastguard Worker 269*9880d681SAndroid Build Coastguard Worker /// \brief Add an expansion subview to this view. 270*9880d681SAndroid Build Coastguard Worker void addExpansion(const coverage::CounterMappingRegion &Region, 271*9880d681SAndroid Build Coastguard Worker std::unique_ptr<SourceCoverageView> View); 272*9880d681SAndroid Build Coastguard Worker 273*9880d681SAndroid Build Coastguard Worker /// \brief Add a function instantiation subview to this view. 274*9880d681SAndroid Build Coastguard Worker void addInstantiation(StringRef FunctionName, unsigned Line, 275*9880d681SAndroid Build Coastguard Worker std::unique_ptr<SourceCoverageView> View); 276*9880d681SAndroid Build Coastguard Worker 277*9880d681SAndroid Build Coastguard Worker /// \brief Print the code coverage information for a specific portion of a 278*9880d681SAndroid Build Coastguard Worker /// source file to the output stream. 279*9880d681SAndroid Build Coastguard Worker void print(raw_ostream &OS, bool WholeFile, bool ShowSourceName, 280*9880d681SAndroid Build Coastguard Worker unsigned ViewDepth = 0); 281*9880d681SAndroid Build Coastguard Worker }; 282*9880d681SAndroid Build Coastguard Worker 283*9880d681SAndroid Build Coastguard Worker } // namespace llvm 284*9880d681SAndroid Build Coastguard Worker 285*9880d681SAndroid Build Coastguard Worker #endif // LLVM_COV_SOURCECOVERAGEVIEW_H 286