| 1 | // Copyright (C) 2021 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 |
| 3 | |
| 4 | #ifndef CONFIG_H |
| 5 | #define CONFIG_H |
| 6 | |
| 7 | #include "location.h" |
| 8 | #include "qdoccommandlineparser.h" |
| 9 | #include "singleton.h" |
| 10 | |
| 11 | #include <QtCore/qmap.h> |
| 12 | #include <QtCore/qset.h> |
| 13 | #include <QtCore/qstack.h> |
| 14 | #include <QtCore/qstringlist.h> |
| 15 | |
| 16 | #include <set> |
| 17 | #include <utility> |
| 18 | |
| 19 | QT_BEGIN_NAMESPACE |
| 20 | |
| 21 | class Config; |
| 22 | |
| 23 | /* |
| 24 | Contains information about a location |
| 25 | where a ConfigVar string needs to be expanded |
| 26 | from another config variable. |
| 27 | */ |
| 28 | struct ExpandVar |
| 29 | { |
| 30 | int m_valueIndex {}; |
| 31 | int m_index {}; |
| 32 | QString m_var {}; |
| 33 | QChar m_delim {}; |
| 34 | |
| 35 | ExpandVar(int valueIndex, int index, QString var, const QChar &delim) |
| 36 | : m_valueIndex(valueIndex), m_index(index), m_var(std::move(var)), m_delim(delim) |
| 37 | { |
| 38 | } |
| 39 | }; |
| 40 | |
| 41 | class ConfigVar |
| 42 | { |
| 43 | public: |
| 44 | struct ConfigValue { |
| 45 | QString m_value; |
| 46 | QString m_path; |
| 47 | }; |
| 48 | |
| 49 | [[nodiscard]] QString asString(const QString defaultString = QString()) const; |
| 50 | [[nodiscard]] QStringList asStringList() const; |
| 51 | [[nodiscard]] QSet<QString> asStringSet() const; |
| 52 | [[nodiscard]] bool asBool() const; |
| 53 | [[nodiscard]] int asInt() const; |
| 54 | [[nodiscard]] const Location &location() const { return m_location; } |
| 55 | |
| 56 | ConfigVar() = default; |
| 57 | ConfigVar(QString name, const QStringList &values, const QString &dir, |
| 58 | const Location &loc = Location(), |
| 59 | const QList<ExpandVar> &expandVars = QList<ExpandVar>()) |
| 60 | : m_name(std::move(name)), m_location(loc), m_expandVars(expandVars) |
| 61 | { |
| 62 | for (const auto &v : values) |
| 63 | m_values << ConfigValue {.m_value: v, .m_path: dir}; |
| 64 | } |
| 65 | |
| 66 | private: |
| 67 | void append(const ConfigVar &other); |
| 68 | |
| 69 | private: |
| 70 | QString m_name {}; |
| 71 | QList<ConfigValue> m_values {}; |
| 72 | Location m_location {}; |
| 73 | QList<ExpandVar> m_expandVars {}; |
| 74 | |
| 75 | friend class Config; |
| 76 | }; |
| 77 | |
| 78 | /* |
| 79 | In this multimap, the key is a config variable name. |
| 80 | */ |
| 81 | typedef QMap<QString, ConfigVar> ConfigVarMap; |
| 82 | |
| 83 | class Config : public Singleton<Config> |
| 84 | { |
| 85 | public: |
| 86 | ~Config(); |
| 87 | |
| 88 | enum QDocPass { Neither, Prepare, Generate }; |
| 89 | |
| 90 | enum PathFlags : unsigned char { |
| 91 | None = 0x0, |
| 92 | // TODO: [unenforced-unclear-validation] |
| 93 | // The Validate flag is used, for example, during the retrival |
| 94 | // of paths in getCanonicalPathList. |
| 95 | // It is unclear what kind of validation it performs, if any, |
| 96 | // and when this validation is required. |
| 97 | // Instead, remove this kind of flag and ensure that any |
| 98 | // amount of required validation is performed during the |
| 99 | // parsing step, if possilbe, and only once. |
| 100 | // Furthemore, ensure any such validation removes some |
| 101 | // uncertainty on dependent subsystems, moving constraints to |
| 102 | // preconditions and expressing them at the API boundaries. |
| 103 | Validate = 0x1, |
| 104 | IncludePaths = 0x2 |
| 105 | }; |
| 106 | |
| 107 | void init(const QString &programName, const QStringList &args); |
| 108 | [[nodiscard]] bool getDebug() const { return m_debug; } |
| 109 | [[nodiscard]] bool getAtomsDump() const { return m_atomsDump; } |
| 110 | [[nodiscard]] bool showInternal() const { return m_showInternal; } |
| 111 | |
| 112 | void clear(); |
| 113 | void reset(); |
| 114 | void load(const QString &fileName); |
| 115 | void setStringList(const QString &var, const QStringList &values); |
| 116 | void insertStringList(const QString &var, const QStringList &values); |
| 117 | |
| 118 | void showHelp(int exitCode = 0) { m_parser.showHelp(exitCode); } |
| 119 | [[nodiscard]] QStringList qdocFiles() const { return m_parser.positionalArguments(); } |
| 120 | [[nodiscard]] const QString &programName() const { return m_prog; } |
| 121 | [[nodiscard]] const Location &location() const { return m_location; } |
| 122 | [[nodiscard]] const ConfigVar &get(const QString &var) const |
| 123 | { |
| 124 | // Avoid injecting default-constructed values to map if var doesn't exist |
| 125 | static ConfigVar empty; |
| 126 | auto it = m_configVars.constFind(key: var); |
| 127 | return (it != m_configVars.constEnd()) ? *it : empty; |
| 128 | } |
| 129 | [[nodiscard]] QString getOutputDir(const QString &format = QString("HTML" )) const; |
| 130 | [[nodiscard]] QSet<QString> getOutputFormats() const; |
| 131 | [[nodiscard]] QStringList getCanonicalPathList(const QString &var, |
| 132 | PathFlags flags = None) const; |
| 133 | [[nodiscard]] QRegularExpression getRegExp(const QString &var) const; |
| 134 | [[nodiscard]] QList<QRegularExpression> getRegExpList(const QString &var) const; |
| 135 | [[nodiscard]] QSet<QString> subVars(const QString &var) const; |
| 136 | QStringList getAllFiles(const QString &filesVar, const QString &dirsVar, |
| 137 | const QSet<QString> &excludedDirs = QSet<QString>(), |
| 138 | const QSet<QString> &excludedFiles = QSet<QString>()); |
| 139 | [[nodiscard]] QString getIncludeFilePath(const QString &fileName) const; |
| 140 | QStringList getExampleQdocFiles(const QSet<QString> &excludedDirs, |
| 141 | const QSet<QString> &excludedFiles); |
| 142 | QStringList getExampleImageFiles(const QSet<QString> &excludedDirs, |
| 143 | const QSet<QString> &excludedFiles); |
| 144 | QString getExampleProjectFile(const QString &examplePath); |
| 145 | |
| 146 | static QStringList loadMaster(const QString &fileName); |
| 147 | static bool isFileExcluded(const QString &fileName, const QSet<QString> &excludedFiles); |
| 148 | static QStringList getFilesHere(const QString &dir, const QString &nameFilter, |
| 149 | const Location &location = Location(), |
| 150 | const QSet<QString> &excludedDirs = QSet<QString>(), |
| 151 | const QSet<QString> &excludedFiles = QSet<QString>()); |
| 152 | static QString findFile(const Location &location, const QStringList &files, |
| 153 | const QStringList &dirs, const QString &fileName, |
| 154 | QString *userFriendlyFilePath = nullptr); |
| 155 | static QString copyFile(const Location &location, const QString &sourceFilePath, |
| 156 | const QString &userFriendlySourceFilePath, |
| 157 | const QString &targetDirPath); |
| 158 | static int numParams(const QString &value); |
| 159 | static void pushWorkingDir(const QString &dir); |
| 160 | static void popWorkingDir(); |
| 161 | bool reportMissingAltTextForImages() { return m_reportMissingAltTextForImages; } |
| 162 | |
| 163 | static const QString dot; |
| 164 | |
| 165 | static bool generateExamples; |
| 166 | static QString installDir; |
| 167 | static QString overrideOutputDir; |
| 168 | static QSet<QString> overrideOutputFormats; |
| 169 | |
| 170 | [[nodiscard]] inline bool singleExec() const; |
| 171 | [[nodiscard]] inline bool dualExec() const; |
| 172 | QStringList &defines() { return m_defines; } |
| 173 | QStringList &dependModules() { return m_dependModules; } |
| 174 | QStringList &includePaths() { return m_includePaths; } |
| 175 | QStringList &indexDirs() { return m_indexDirs; } |
| 176 | [[nodiscard]] QString currentDir() const { return m_currentDir; } |
| 177 | void setCurrentDir(const QString &path) { m_currentDir = path; } |
| 178 | [[nodiscard]] QString previousCurrentDir() const { return m_previousCurrentDir; } |
| 179 | void setPreviousCurrentDir(const QString &path) { m_previousCurrentDir = path; } |
| 180 | |
| 181 | void setQDocPass(const QDocPass &pass) { m_qdocPass = pass; }; |
| 182 | [[nodiscard]] bool preparing() const { return (m_qdocPass == Prepare); } |
| 183 | [[nodiscard]] bool generating() const { return (m_qdocPass == Generate); } |
| 184 | |
| 185 | struct ExcludedPaths { |
| 186 | QSet<QString> excluded_directories; |
| 187 | QSet<QString> excluded_files; |
| 188 | }; |
| 189 | const ExcludedPaths& getExcludedPaths(); |
| 190 | |
| 191 | struct SourceLink { |
| 192 | QString baseUrl; |
| 193 | QString rootPath; |
| 194 | QString linkText; |
| 195 | bool enabled; |
| 196 | }; |
| 197 | const SourceLink &getSourceLink(); |
| 198 | |
| 199 | struct { |
| 200 | QString ; |
| 201 | QString ; |
| 202 | |
| 203 | friend bool (const HeaderFilePath& lhs, const HeaderFilePath& rhs) { |
| 204 | return std::tie(args: lhs.path, args: lhs.filename) < std::tie(args: rhs.path, args: rhs.filename); |
| 205 | } |
| 206 | }; |
| 207 | std::set<HeaderFilePath> (); |
| 208 | |
| 209 | private: |
| 210 | void processCommandLineOptions(const QStringList &args); |
| 211 | void setIncludePaths(); |
| 212 | void setIndexDirs(); |
| 213 | void expandVariables(); |
| 214 | |
| 215 | QStringList m_dependModules {}; |
| 216 | QStringList m_defines {}; |
| 217 | QStringList m_includePaths {}; |
| 218 | QStringList m_indexDirs {}; |
| 219 | QStringList m_exampleFiles {}; |
| 220 | QStringList m_exampleDirs {}; |
| 221 | QString m_currentDir {}; |
| 222 | QString m_previousCurrentDir {}; |
| 223 | std::optional<ExcludedPaths> m_excludedPaths{}; |
| 224 | std::optional<SourceLink> m_sourceLink{}; |
| 225 | |
| 226 | bool m_showInternal { false }; |
| 227 | static bool m_debug; |
| 228 | |
| 229 | // An option that can be set trough a similarly named command-line option. |
| 230 | // When this is set, every time QDoc parses a block-comment, a |
| 231 | // human-readable presentation of the `Atom`s structure for that |
| 232 | // block will shown to the user. |
| 233 | static bool m_atomsDump; |
| 234 | |
| 235 | static bool isMetaKeyChar(QChar ch); |
| 236 | void load(Location location, const QString &fileName); |
| 237 | |
| 238 | QString m_prog {}; |
| 239 | Location m_location {}; |
| 240 | ConfigVarMap m_configVars {}; |
| 241 | |
| 242 | static QMap<QString, QString> ; |
| 243 | static QStack<QString> m_workingDirs; |
| 244 | static QMap<QString, QStringList> m_includeFilesMap; |
| 245 | QDocCommandLineParser m_parser {}; |
| 246 | |
| 247 | QDocPass m_qdocPass { Neither }; |
| 248 | |
| 249 | bool m_reportMissingAltTextForImages{ false }; |
| 250 | }; |
| 251 | |
| 252 | struct ConfigStrings |
| 253 | { |
| 254 | static QString AUTOLINKERRORS; |
| 255 | static QString BUILDVERSION; |
| 256 | static QString CODEINDENT; |
| 257 | static QString CODEPREFIX; |
| 258 | static QString CODESUFFIX; |
| 259 | static QString CPPCLASSESPAGE; |
| 260 | static QString CPPCLASSESTITLE; |
| 261 | static QString DEFINES; |
| 262 | static QString DEPENDS; |
| 263 | static QString DESCRIPTION; |
| 264 | static QString DOCBOOKEXTENSIONS; |
| 265 | static QString ; |
| 266 | static QString ; |
| 267 | static QString EXAMPLEDIRS; |
| 268 | static QString EXAMPLES; |
| 269 | static QString EXAMPLESINSTALLPATH; |
| 270 | static QString EXCLUDEDIRS; |
| 271 | static QString EXCLUDEFILES; |
| 272 | static QString ; |
| 273 | static QString FALSEHOODS; |
| 274 | static QString FORMATTING; |
| 275 | static QString ; |
| 276 | static QString ; |
| 277 | static QString ; |
| 278 | static QString ; |
| 279 | static QString HOMEPAGE; |
| 280 | static QString HOMETITLE; |
| 281 | static QString IGNOREDIRECTIVES; |
| 282 | static QString IGNORETOKENS; |
| 283 | static QString IGNORESINCE; |
| 284 | static QString IGNOREWORDS; |
| 285 | static QString IMAGEDIRS; |
| 286 | static QString IMAGES; |
| 287 | static QString INCLUDEPATHS; |
| 288 | static QString INCLUSIVE; |
| 289 | static QString INDEXES; |
| 290 | static QString LANDINGPAGE; |
| 291 | static QString LANDINGTITLE; |
| 292 | static QString LANGUAGE; |
| 293 | static QString LOCATIONINFO; |
| 294 | static QString LOGPROGRESS; |
| 295 | static QString MACRO; |
| 296 | static QString MANIFESTMETA; |
| 297 | static QString ; |
| 298 | static QString NATURALLANGUAGE; |
| 299 | static QString NAVIGATION; |
| 300 | static QString NOLINKERRORS; |
| 301 | static QString OUTPUTDIR; |
| 302 | static QString OUTPUTFORMATS; |
| 303 | static QString OUTPUTPREFIXES; |
| 304 | static QString OUTPUTSUFFIXES; |
| 305 | static QString PRODUCTNAME; |
| 306 | static QString PROJECT; |
| 307 | static QString REDIRECTDOCUMENTATIONTODEVNULL; |
| 308 | static QString REPORTMISSINGALTTEXTFORIMAGES; |
| 309 | static QString QHP; |
| 310 | static QString QUOTINGINFORMATION; |
| 311 | static QString ROOTDIR; |
| 312 | static QString SCRIPTS; |
| 313 | static QString SHOWINTERNAL; |
| 314 | static QString SINGLEEXEC; |
| 315 | static QString SOURCEDIRS; |
| 316 | static QString SOURCEENCODING; |
| 317 | static QString SOURCES; |
| 318 | static QString SPURIOUS; |
| 319 | static QString STYLESHEETS; |
| 320 | static QString SYNTAXHIGHLIGHTING; |
| 321 | static QString TABSIZE; |
| 322 | static QString TAGFILE; |
| 323 | static QString TIMESTAMPS; |
| 324 | static QString TOCTITLES; |
| 325 | static QString TRADEMARKSPAGE; |
| 326 | static QString URL; |
| 327 | static QString USEALTTEXTASTITLE; |
| 328 | static QString VERSION; |
| 329 | static QString VERSIONSYM; |
| 330 | static QString FILEEXTENSIONS; |
| 331 | static QString IMAGEEXTENSIONS; |
| 332 | static QString QMLTYPESPAGE; |
| 333 | static QString QMLTYPESTITLE; |
| 334 | static QString WARNABOUTMISSINGIMAGES; |
| 335 | static QString WARNABOUTMISSINGPROJECTFILES; |
| 336 | static QString WARNINGLIMIT; |
| 337 | }; |
| 338 | |
| 339 | #define CONFIG_AUTOLINKERRORS ConfigStrings::AUTOLINKERRORS |
| 340 | #define CONFIG_BUILDVERSION ConfigStrings::BUILDVERSION |
| 341 | #define CONFIG_CODEINDENT ConfigStrings::CODEINDENT |
| 342 | #define CONFIG_CODEPREFIX ConfigStrings::CODEPREFIX |
| 343 | #define CONFIG_CODESUFFIX ConfigStrings::CODESUFFIX |
| 344 | #define CONFIG_CPPCLASSESPAGE ConfigStrings::CPPCLASSESPAGE |
| 345 | #define CONFIG_CPPCLASSESTITLE ConfigStrings::CPPCLASSESTITLE |
| 346 | #define CONFIG_DEFINES ConfigStrings::DEFINES |
| 347 | #define CONFIG_DEPENDS ConfigStrings::DEPENDS |
| 348 | #define CONFIG_DESCRIPTION ConfigStrings::DESCRIPTION |
| 349 | #define CONFIG_DOCBOOKEXTENSIONS ConfigStrings::DOCBOOKEXTENSIONS |
| 350 | #define ConfigStrings::DOCUMENTATIONINHEADERS |
| 351 | #define ConfigStrings::ENDHEADER |
| 352 | #define CONFIG_EXAMPLEDIRS ConfigStrings::EXAMPLEDIRS |
| 353 | #define CONFIG_EXAMPLES ConfigStrings::EXAMPLES |
| 354 | #define CONFIG_EXAMPLESINSTALLPATH ConfigStrings::EXAMPLESINSTALLPATH |
| 355 | #define CONFIG_EXCLUDEDIRS ConfigStrings::EXCLUDEDIRS |
| 356 | #define CONFIG_EXCLUDEFILES ConfigStrings::EXCLUDEFILES |
| 357 | #define ConfigStrings::EXTRAIMAGES |
| 358 | #define CONFIG_FALSEHOODS ConfigStrings::FALSEHOODS |
| 359 | #define CONFIG_FORMATTING ConfigStrings::FORMATTING |
| 360 | #define ConfigStrings::HEADERDIRS |
| 361 | #define ConfigStrings::HEADERS |
| 362 | #define ConfigStrings::HEADERSCRIPTS |
| 363 | #define ConfigStrings::HEADERSTYLES |
| 364 | #define CONFIG_HOMEPAGE ConfigStrings::HOMEPAGE |
| 365 | #define CONFIG_HOMETITLE ConfigStrings::HOMETITLE |
| 366 | #define CONFIG_IGNOREDIRECTIVES ConfigStrings::IGNOREDIRECTIVES |
| 367 | #define CONFIG_IGNORESINCE ConfigStrings::IGNORESINCE |
| 368 | #define CONFIG_IGNORETOKENS ConfigStrings::IGNORETOKENS |
| 369 | #define CONFIG_IGNOREWORDS ConfigStrings::IGNOREWORDS |
| 370 | #define CONFIG_IMAGEDIRS ConfigStrings::IMAGEDIRS |
| 371 | #define CONFIG_INCLUDEPATHS ConfigStrings::INCLUDEPATHS |
| 372 | #define CONFIG_INCLUSIVE ConfigStrings::INCLUSIVE |
| 373 | #define CONFIG_INDEXES ConfigStrings::INDEXES |
| 374 | #define CONFIG_LANDINGPAGE ConfigStrings::LANDINGPAGE |
| 375 | #define CONFIG_LANDINGTITLE ConfigStrings::LANDINGTITLE |
| 376 | #define CONFIG_LANGUAGE ConfigStrings::LANGUAGE |
| 377 | #define CONFIG_LOCATIONINFO ConfigStrings::LOCATIONINFO |
| 378 | #define CONFIG_LOGPROGRESS ConfigStrings::LOGPROGRESS |
| 379 | #define CONFIG_MACRO ConfigStrings::MACRO |
| 380 | #define CONFIG_MANIFESTMETA ConfigStrings::MANIFESTMETA |
| 381 | #define ConfigStrings::MODULEHEADER |
| 382 | #define CONFIG_NATURALLANGUAGE ConfigStrings::NATURALLANGUAGE |
| 383 | #define CONFIG_NAVIGATION ConfigStrings::NAVIGATION |
| 384 | #define CONFIG_NOLINKERRORS ConfigStrings::NOLINKERRORS |
| 385 | #define CONFIG_OUTPUTDIR ConfigStrings::OUTPUTDIR |
| 386 | #define CONFIG_OUTPUTFORMATS ConfigStrings::OUTPUTFORMATS |
| 387 | #define CONFIG_OUTPUTPREFIXES ConfigStrings::OUTPUTPREFIXES |
| 388 | #define CONFIG_OUTPUTSUFFIXES ConfigStrings::OUTPUTSUFFIXES |
| 389 | #define CONFIG_PRODUCTNAME ConfigStrings::PRODUCTNAME |
| 390 | #define CONFIG_PROJECT ConfigStrings::PROJECT |
| 391 | #define CONFIG_REDIRECTDOCUMENTATIONTODEVNULL ConfigStrings::REDIRECTDOCUMENTATIONTODEVNULL |
| 392 | #define CONFIG_REPORTMISSINGALTTEXTFORIMAGES ConfigStrings::REPORTMISSINGALTTEXTFORIMAGES |
| 393 | #define CONFIG_QHP ConfigStrings::QHP |
| 394 | #define CONFIG_QUOTINGINFORMATION ConfigStrings::QUOTINGINFORMATION |
| 395 | #define CONFIG_ROOTDIR ConfigStrings::ROOTDIR |
| 396 | #define CONFIG_SCRIPTS ConfigStrings::SCRIPTS |
| 397 | #define CONFIG_SHOWINTERNAL ConfigStrings::SHOWINTERNAL |
| 398 | #define CONFIG_SINGLEEXEC ConfigStrings::SINGLEEXEC |
| 399 | #define CONFIG_SOURCEDIRS ConfigStrings::SOURCEDIRS |
| 400 | #define CONFIG_SOURCEENCODING ConfigStrings::SOURCEENCODING |
| 401 | #define CONFIG_SOURCES ConfigStrings::SOURCES |
| 402 | #define CONFIG_SPURIOUS ConfigStrings::SPURIOUS |
| 403 | #define CONFIG_STYLESHEETS ConfigStrings::STYLESHEETS |
| 404 | #define CONFIG_SYNTAXHIGHLIGHTING ConfigStrings::SYNTAXHIGHLIGHTING |
| 405 | #define CONFIG_TABSIZE ConfigStrings::TABSIZE |
| 406 | #define CONFIG_TAGFILE ConfigStrings::TAGFILE |
| 407 | #define CONFIG_TIMESTAMPS ConfigStrings::TIMESTAMPS |
| 408 | #define CONFIG_TOCTITLES ConfigStrings::TOCTITLES |
| 409 | #define CONFIG_TRADEMARKSPAGE ConfigStrings::TRADEMARKSPAGE |
| 410 | #define CONFIG_URL ConfigStrings::URL |
| 411 | #define CONFIG_USEALTTEXTASTITLE ConfigStrings::USEALTTEXTASTITLE |
| 412 | #define CONFIG_VERSION ConfigStrings::VERSION |
| 413 | #define CONFIG_VERSIONSYM ConfigStrings::VERSIONSYM |
| 414 | #define CONFIG_FILEEXTENSIONS ConfigStrings::FILEEXTENSIONS |
| 415 | #define CONFIG_IMAGEEXTENSIONS ConfigStrings::IMAGEEXTENSIONS |
| 416 | #define CONFIG_QMLTYPESPAGE ConfigStrings::QMLTYPESPAGE |
| 417 | #define CONFIG_QMLTYPESTITLE ConfigStrings::QMLTYPESTITLE |
| 418 | #define CONFIG_WARNABOUTMISSINGIMAGES ConfigStrings::WARNABOUTMISSINGIMAGES |
| 419 | #define CONFIG_WARNABOUTMISSINGPROJECTFILES ConfigStrings::WARNABOUTMISSINGPROJECTFILES |
| 420 | #define CONFIG_WARNINGLIMIT ConfigStrings::WARNINGLIMIT |
| 421 | |
| 422 | inline bool Config::singleExec() const |
| 423 | { |
| 424 | return m_configVars.value(CONFIG_SINGLEEXEC).asBool(); |
| 425 | } |
| 426 | |
| 427 | inline bool Config::dualExec() const |
| 428 | { |
| 429 | return !m_configVars.value(CONFIG_SINGLEEXEC).asBool(); |
| 430 | } |
| 431 | |
| 432 | QT_END_NAMESPACE |
| 433 | |
| 434 | #endif |
| 435 | |