├── composer.json ├── src └── WpContext.php └── LICENSE /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "inpsyde/wp-context", 3 | "type": "library", 4 | "description": "A single-class utility to check the running context in WordPress sites.", 5 | "license": "GPL-2.0-or-later", 6 | "authors": [ 7 | { 8 | "name": "Syde GmbH", 9 | "homepage": "https://syde.com/", 10 | "email": "hello@syde.com", 11 | "role": "Company" 12 | }, 13 | { 14 | "name": "Giuseppe Mazzapica", 15 | "email": "g.mazzapica@inpsyde.com", 16 | "role": "Developer" 17 | } 18 | ], 19 | "require": { 20 | "php": ">=7.1" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "~7.5.20 || ^8", 24 | "inpsyde/php-coding-standards": "^1", 25 | "vimeo/psalm": "^4.27.0", 26 | "mockery/mockery": "~1.3.6", 27 | "brain/monkey": "^2.6.1", 28 | "inpsyde/wp-stubs": "dev-main" 29 | }, 30 | "autoload": { 31 | "psr-4": { 32 | "Inpsyde\\": "src/" 33 | } 34 | }, 35 | "autoload-dev": { 36 | "psr-4": { 37 | "Inpsyde\\Tests\\": "tests/" 38 | } 39 | }, 40 | "minimum-stability": "dev", 41 | "prefer-stable": true, 42 | "scripts": { 43 | "cs": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs", 44 | "psalm": "@php ./vendor/vimeo/psalm/psalm --no-cache --output-format=compact", 45 | "tests": "@php ./vendor/phpunit/phpunit/phpunit", 46 | "tests:no-cov": "@php ./vendor/phpunit/phpunit/phpunit --no-coverage", 47 | "phpcompat": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs -p . --standard=PHPCompatibility --ignore=*/vendor/* --extensions=php --basepath=./ --runtime-set testVersion 7.1-", 48 | "qa": [ 49 | "@cs", 50 | "@phpcompat", 51 | "@psalm", 52 | "@tests:no-cov" 53 | ] 54 | }, 55 | "config": { 56 | "optimize-autoloader": true, 57 | "allow-plugins": { 58 | "dealerdirect/phpcodesniffer-composer-installer": true, 59 | "inpsyde/*": true, 60 | "composer/*": true 61 | } 62 | }, 63 | "extra": { 64 | "branch-alias": { 65 | "dev-main": "1.x-dev" 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/WpContext.php: -------------------------------------------------------------------------------- 1 | 42 | */ 43 | private $actionCallbacks = []; 44 | 45 | /** 46 | * @return WpContext 47 | */ 48 | final public static function new(): WpContext 49 | { 50 | return new self(array_fill_keys(self::ALL, false)); 51 | } 52 | 53 | /** 54 | * @return WpContext 55 | */ 56 | final public static function determine(): WpContext 57 | { 58 | /** @psalm-suppress RedundantCondition */ 59 | $installing = defined('WP_INSTALLING') && WP_INSTALLING; 60 | /** @psalm-suppress RedundantCondition */ 61 | $xmlRpc = defined('XMLRPC_REQUEST') && XMLRPC_REQUEST; 62 | $isCore = defined('ABSPATH'); 63 | $isCli = defined('WP_CLI'); 64 | $notInstalling = $isCore && !$installing; 65 | $isAjax = $notInstalling && wp_doing_ajax(); 66 | $isAdmin = $notInstalling && is_admin() && !$isAjax; 67 | $isCron = $notInstalling && wp_doing_cron(); 68 | $isWpActivate = $installing && is_multisite() && self::isWpActivateRequest(); 69 | 70 | $undetermined = $notInstalling && !$isAdmin && !$isCron && !$isCli && !$xmlRpc && !$isAjax; 71 | 72 | $isRest = $undetermined && static::isRestRequest(); 73 | $isLogin = $undetermined && !$isRest && static::isLoginRequest(); 74 | 75 | // When nothing else matches, we assume it is a front-office request. 76 | $isFront = $undetermined && !$isRest && !$isLogin; 77 | 78 | /* 79 | * Note that when core is installing **only** `INSTALLING` will be true, not even `CORE`. 80 | * This is done to do as less as possible during installation, when most of WP does not act 81 | * as expected. 82 | */ 83 | 84 | $instance = new self( 85 | [ 86 | self::AJAX => $isAjax, 87 | self::BACKOFFICE => $isAdmin, 88 | self::CLI => $isCli, 89 | self::CORE => ($isCore || $xmlRpc) && (!$installing || $isWpActivate), 90 | self::CRON => $isCron, 91 | self::FRONTOFFICE => $isFront, 92 | self::INSTALLING => $installing && !$isWpActivate, 93 | self::LOGIN => $isLogin, 94 | self::REST => $isRest, 95 | self::XML_RPC => $xmlRpc && !$installing, 96 | self::WP_ACTIVATE => $isWpActivate, 97 | ] 98 | ); 99 | 100 | $instance->addActionHooks(); 101 | 102 | return $instance; 103 | } 104 | 105 | /** 106 | * @return bool 107 | */ 108 | private static function isRestRequest(): bool 109 | { 110 | /** @psalm-suppress RedundantCondition */ 111 | $isRestRequest = defined('REST_REQUEST') && REST_REQUEST; 112 | if ($isRestRequest || !empty($_GET['rest_route'])) { // phpcs:ignore 113 | return true; 114 | } 115 | 116 | if (!get_option('permalink_structure')) { 117 | return false; 118 | } 119 | 120 | /* 121 | * This is needed because, if called early, global $wp_rewrite is not defined but required 122 | * by get_rest_url(). WP will reuse what we set here, or in worst case will replace, but no 123 | * consequences for us in any case. 124 | */ 125 | if (empty($GLOBALS['wp_rewrite'])) { 126 | $GLOBALS['wp_rewrite'] = new \WP_Rewrite(); 127 | } 128 | 129 | $currentPath = trim((string)parse_url((string)add_query_arg([]), PHP_URL_PATH), '/') . '/'; 130 | $restPath = trim((string)parse_url((string)get_rest_url(), PHP_URL_PATH), '/') . '/'; 131 | 132 | return strpos($currentPath, $restPath) === 0; 133 | } 134 | 135 | /** 136 | * @return bool 137 | */ 138 | private static function isLoginRequest(): bool 139 | { 140 | /** 141 | * New core function with WordPress 6.1 142 | * @link https://make.wordpress.org/core/2022/09/11/new-is_login-function-for-determining-if-a-page-is-the-login-screen/ 143 | */ 144 | if (function_exists('is_login')) { 145 | return is_login() !== false; 146 | } 147 | 148 | if (!empty($_REQUEST['interim-login'])) { // phpcs:ignore 149 | return true; 150 | } 151 | 152 | /** 153 | * Fallback and 1:1 copy from is_login() in case, the function is 154 | * not available for WP < 6.1. 155 | * phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotValidated 156 | * phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash 157 | * phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized 158 | */ 159 | $scriptName = $_SERVER['SCRIPT_NAME'] ?? ''; 160 | 161 | return false !== stripos(wp_login_url(), $scriptName); 162 | } 163 | 164 | /** 165 | * @return bool 166 | */ 167 | private static function isWpActivateRequest(): bool 168 | { 169 | return static::isPageNow('wp-activate.php', network_site_url('wp-activate.php')); 170 | } 171 | 172 | /** 173 | * @param string $page 174 | * @param string $url 175 | * @return bool 176 | */ 177 | private static function isPageNow(string $page, string $url): bool 178 | { 179 | $pageNow = (string)($GLOBALS['pagenow'] ?? ''); 180 | if ($pageNow && (basename($pageNow) === $page)) { 181 | return true; 182 | } 183 | 184 | $currentPath = (string)parse_url(add_query_arg([]), PHP_URL_PATH); 185 | $targetPath = (string)parse_url($url, PHP_URL_PATH); 186 | 187 | return trim($currentPath, '/') === trim($targetPath, '/'); 188 | } 189 | 190 | /** 191 | * @param array $data 192 | */ 193 | private function __construct(array $data) 194 | { 195 | $this->data = $data; 196 | } 197 | 198 | /** 199 | * @param string $context 200 | * @return WpContext 201 | */ 202 | final public function force(string $context): WpContext 203 | { 204 | if (!in_array($context, self::ALL, true)) { 205 | throw new \LogicException("'{$context}' is not a valid context."); 206 | } 207 | 208 | $this->removeActionHooks(); 209 | 210 | $data = array_fill_keys(self::ALL, false); 211 | $data[$context] = true; 212 | if (!in_array($context, [self::INSTALLING, self::CLI, self::CORE], true)) { 213 | $data[self::CORE] = true; 214 | } 215 | 216 | $this->data = $data; 217 | 218 | return $this; 219 | } 220 | 221 | /** 222 | * @return WpContext 223 | */ 224 | final public function withCli(): WpContext 225 | { 226 | $this->data[self::CLI] = true; 227 | 228 | return $this; 229 | } 230 | 231 | /** 232 | * @param string $context 233 | * @param string ...$contexts 234 | * @return bool 235 | */ 236 | final public function is(string $context, string ...$contexts): bool 237 | { 238 | array_unshift($contexts, $context); 239 | 240 | foreach ($contexts as $context) { 241 | if (($this->data[$context] ?? null)) { 242 | return true; 243 | } 244 | } 245 | 246 | return false; 247 | } 248 | 249 | /** 250 | * @return bool 251 | */ 252 | public function isCore(): bool 253 | { 254 | return $this->is(self::CORE); 255 | } 256 | 257 | /** 258 | * @return bool 259 | */ 260 | public function isFrontoffice(): bool 261 | { 262 | return $this->is(self::FRONTOFFICE); 263 | } 264 | 265 | /** 266 | * @return bool 267 | */ 268 | public function isBackoffice(): bool 269 | { 270 | return $this->is(self::BACKOFFICE); 271 | } 272 | 273 | /** 274 | * @return bool 275 | */ 276 | public function isAjax(): bool 277 | { 278 | return $this->is(self::AJAX); 279 | } 280 | 281 | /** 282 | * @return bool 283 | */ 284 | public function isLogin(): bool 285 | { 286 | return $this->is(self::LOGIN); 287 | } 288 | 289 | /** 290 | * @return bool 291 | */ 292 | public function isRest(): bool 293 | { 294 | return $this->is(self::REST); 295 | } 296 | 297 | /** 298 | * @return bool 299 | */ 300 | public function isCron(): bool 301 | { 302 | return $this->is(self::CRON); 303 | } 304 | 305 | /** 306 | * @return bool 307 | */ 308 | public function isWpCli(): bool 309 | { 310 | return $this->is(self::CLI); 311 | } 312 | 313 | /** 314 | * @return bool 315 | */ 316 | public function isXmlRpc(): bool 317 | { 318 | return $this->is(self::XML_RPC); 319 | } 320 | 321 | /** 322 | * @return bool 323 | */ 324 | public function isInstalling(): bool 325 | { 326 | return $this->is(self::INSTALLING); 327 | } 328 | 329 | /** 330 | * @return bool 331 | */ 332 | public function isWpActivate(): bool 333 | { 334 | return $this->is(self::WP_ACTIVATE); 335 | } 336 | 337 | /** 338 | * @return array 339 | */ 340 | public function jsonSerialize(): array 341 | { 342 | return $this->data; 343 | } 344 | 345 | /** 346 | * When context is determined very early we do our best to understand some context like 347 | * login, rest and front-office even if WordPress normally would require a later hook. 348 | * When that later hook happen, we change what we have determined, leveraging the more 349 | * "core-compliant" approach. 350 | * 351 | * @return void 352 | */ 353 | private function addActionHooks(): void 354 | { 355 | $this->actionCallbacks = [ 356 | 'login_init' => function (): void { 357 | $this->resetAndForce(self::LOGIN); 358 | }, 359 | 'rest_api_init' => function (): void { 360 | $this->resetAndForce(self::REST); 361 | }, 362 | 'activate_header' => function (): void { 363 | $this->resetAndForce(self::WP_ACTIVATE); 364 | }, 365 | 'template_redirect' => function (): void { 366 | $this->resetAndForce(self::FRONTOFFICE); 367 | }, 368 | 'current_screen' => function (\WP_Screen $screen): void { 369 | $screen->in_admin() and $this->resetAndForce(self::BACKOFFICE); 370 | }, 371 | ]; 372 | 373 | foreach ($this->actionCallbacks as $action => $callback) { 374 | /** @psalm-suppress MixedArgument */ 375 | add_action($action, $callback, PHP_INT_MIN); 376 | } 377 | } 378 | 379 | /** 380 | * When "force" is called on an instance created via `determine()` we need to remove added hooks 381 | * or what we are forcing might be overridden. 382 | * 383 | * @return void 384 | */ 385 | private function removeActionHooks(): void 386 | { 387 | foreach ($this->actionCallbacks as $action => $callback) { 388 | /** @psalm-suppress MixedArgument */ 389 | remove_action($action, $callback, PHP_INT_MIN); 390 | } 391 | $this->actionCallbacks = []; 392 | } 393 | 394 | /** 395 | * @param string $context 396 | * @return void 397 | */ 398 | private function resetAndForce(string $context): void 399 | { 400 | $cli = $this->isWpCli(); 401 | $this->force($context); 402 | $cli and $this->withCli(); 403 | } 404 | } 405 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ### GNU GENERAL PUBLIC LICENSE 2 | 3 | Version 2, June 1991 4 | 5 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 6 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 7 | 8 | Everyone is permitted to copy and distribute verbatim copies 9 | of this license document, but changing it is not allowed. 10 | 11 | ### Preamble 12 | 13 | The licenses for most software are designed to take away your freedom 14 | to share and change it. By contrast, the GNU General Public License is 15 | intended to guarantee your freedom to share and change free 16 | software--to make sure the software is free for all its users. This 17 | General Public License applies to most of the Free Software 18 | Foundation's software and to any other program whose authors commit to 19 | using it. (Some other Free Software Foundation software is covered by 20 | the GNU Lesser General Public License instead.) You can apply it to 21 | your programs, too. 22 | 23 | When we speak of free software, we are referring to freedom, not 24 | price. Our General Public Licenses are designed to make sure that you 25 | have the freedom to distribute copies of free software (and charge for 26 | this service if you wish), that you receive source code or can get it 27 | if you want it, that you can change the software or use pieces of it 28 | in new free programs; and that you know you can do these things. 29 | 30 | To protect your rights, we need to make restrictions that forbid 31 | anyone to deny you these rights or to ask you to surrender the rights. 32 | These restrictions translate to certain responsibilities for you if 33 | you distribute copies of the software, or if you modify it. 34 | 35 | For example, if you distribute copies of such a program, whether 36 | gratis or for a fee, you must give the recipients all the rights that 37 | you have. You must make sure that they, too, receive or can get the 38 | source code. And you must show them these terms so they know their 39 | rights. 40 | 41 | We protect your rights with two steps: (1) copyright the software, and 42 | (2) offer you this license which gives you legal permission to copy, 43 | distribute and/or modify the software. 44 | 45 | Also, for each author's protection and ours, we want to make certain 46 | that everyone understands that there is no warranty for this free 47 | software. If the software is modified by someone else and passed on, 48 | we want its recipients to know that what they have is not the 49 | original, so that any problems introduced by others will not reflect 50 | on the original authors' reputations. 51 | 52 | Finally, any free program is threatened constantly by software 53 | patents. We wish to avoid the danger that redistributors of a free 54 | program will individually obtain patent licenses, in effect making the 55 | program proprietary. To prevent this, we have made it clear that any 56 | patent must be licensed for everyone's free use or not licensed at 57 | all. 58 | 59 | The precise terms and conditions for copying, distribution and 60 | modification follow. 61 | 62 | ### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 63 | 64 | **0.** This License applies to any program or other work which 65 | contains a notice placed by the copyright holder saying it may be 66 | distributed under the terms of this General Public License. The 67 | "Program", below, refers to any such program or work, and a "work 68 | based on the Program" means either the Program or any derivative work 69 | under copyright law: that is to say, a work containing the Program or 70 | a portion of it, either verbatim or with modifications and/or 71 | translated into another language. (Hereinafter, translation is 72 | included without limitation in the term "modification".) Each licensee 73 | is addressed as "you". 74 | 75 | Activities other than copying, distribution and modification are not 76 | covered by this License; they are outside its scope. The act of 77 | running the Program is not restricted, and the output from the Program 78 | is covered only if its contents constitute a work based on the Program 79 | (independent of having been made by running the Program). Whether that 80 | is true depends on what the Program does. 81 | 82 | **1.** You may copy and distribute verbatim copies of the Program's 83 | source code as you receive it, in any medium, provided that you 84 | conspicuously and appropriately publish on each copy an appropriate 85 | copyright notice and disclaimer of warranty; keep intact all the 86 | notices that refer to this License and to the absence of any warranty; 87 | and give any other recipients of the Program a copy of this License 88 | along with the Program. 89 | 90 | You may charge a fee for the physical act of transferring a copy, and 91 | you may at your option offer warranty protection in exchange for a 92 | fee. 93 | 94 | **2.** You may modify your copy or copies of the Program or any 95 | portion of it, thus forming a work based on the Program, and copy and 96 | distribute such modifications or work under the terms of Section 1 97 | above, provided that you also meet all of these conditions: 98 | 99 | 100 | **a)** You must cause the modified files to carry prominent notices 101 | stating that you changed the files and the date of any change. 102 | 103 | 104 | **b)** You must cause any work that you distribute or publish, that in 105 | whole or in part contains or is derived from the Program or any part 106 | thereof, to be licensed as a whole at no charge to all third parties 107 | under the terms of this License. 108 | 109 | 110 | **c)** If the modified program normally reads commands interactively 111 | when run, you must cause it, when started running for such interactive 112 | use in the most ordinary way, to print or display an announcement 113 | including an appropriate copyright notice and a notice that there is 114 | no warranty (or else, saying that you provide a warranty) and that 115 | users may redistribute the program under these conditions, and telling 116 | the user how to view a copy of this License. (Exception: if the 117 | Program itself is interactive but does not normally print such an 118 | announcement, your work based on the Program is not required to print 119 | an announcement.) 120 | 121 | These requirements apply to the modified work as a whole. If 122 | identifiable sections of that work are not derived from the Program, 123 | and can be reasonably considered independent and separate works in 124 | themselves, then this License, and its terms, do not apply to those 125 | sections when you distribute them as separate works. But when you 126 | distribute the same sections as part of a whole which is a work based 127 | on the Program, the distribution of the whole must be on the terms of 128 | this License, whose permissions for other licensees extend to the 129 | entire whole, and thus to each and every part regardless of who wrote 130 | it. 131 | 132 | Thus, it is not the intent of this section to claim rights or contest 133 | your rights to work written entirely by you; rather, the intent is to 134 | exercise the right to control the distribution of derivative or 135 | collective works based on the Program. 136 | 137 | In addition, mere aggregation of another work not based on the Program 138 | with the Program (or with a work based on the Program) on a volume of 139 | a storage or distribution medium does not bring the other work under 140 | the scope of this License. 141 | 142 | **3.** You may copy and distribute the Program (or a work based on it, 143 | under Section 2) in object code or executable form under the terms of 144 | Sections 1 and 2 above provided that you also do one of the following: 145 | 146 | 147 | **a)** Accompany it with the complete corresponding machine-readable 148 | source code, which must be distributed under the terms of Sections 1 149 | and 2 above on a medium customarily used for software interchange; or, 150 | 151 | 152 | **b)** Accompany it with a written offer, valid for at least three 153 | years, to give any third party, for a charge no more than your cost of 154 | physically performing source distribution, a complete machine-readable 155 | copy of the corresponding source code, to be distributed under the 156 | terms of Sections 1 and 2 above on a medium customarily used for 157 | software interchange; or, 158 | 159 | 160 | **c)** Accompany it with the information you received as to the offer 161 | to distribute corresponding source code. (This alternative is allowed 162 | only for noncommercial distribution and only if you received the 163 | program in object code or executable form with such an offer, in 164 | accord with Subsection b above.) 165 | 166 | The source code for a work means the preferred form of the work for 167 | making modifications to it. For an executable work, complete source 168 | code means all the source code for all modules it contains, plus any 169 | associated interface definition files, plus the scripts used to 170 | control compilation and installation of the executable. However, as a 171 | special exception, the source code distributed need not include 172 | anything that is normally distributed (in either source or binary 173 | form) with the major components (compiler, kernel, and so on) of the 174 | operating system on which the executable runs, unless that component 175 | itself accompanies the executable. 176 | 177 | If distribution of executable or object code is made by offering 178 | access to copy from a designated place, then offering equivalent 179 | access to copy the source code from the same place counts as 180 | distribution of the source code, even though third parties are not 181 | compelled to copy the source along with the object code. 182 | 183 | **4.** You may not copy, modify, sublicense, or distribute the Program 184 | except as expressly provided under this License. Any attempt otherwise 185 | to copy, modify, sublicense or distribute the Program is void, and 186 | will automatically terminate your rights under this License. However, 187 | parties who have received copies, or rights, from you under this 188 | License will not have their licenses terminated so long as such 189 | parties remain in full compliance. 190 | 191 | **5.** You are not required to accept this License, since you have not 192 | signed it. However, nothing else grants you permission to modify or 193 | distribute the Program or its derivative works. These actions are 194 | prohibited by law if you do not accept this License. Therefore, by 195 | modifying or distributing the Program (or any work based on the 196 | Program), you indicate your acceptance of this License to do so, and 197 | all its terms and conditions for copying, distributing or modifying 198 | the Program or works based on it. 199 | 200 | **6.** Each time you redistribute the Program (or any work based on 201 | the Program), the recipient automatically receives a license from the 202 | original licensor to copy, distribute or modify the Program subject to 203 | these terms and conditions. You may not impose any further 204 | restrictions on the recipients' exercise of the rights granted herein. 205 | You are not responsible for enforcing compliance by third parties to 206 | this License. 207 | 208 | **7.** If, as a consequence of a court judgment or allegation of 209 | patent infringement or for any other reason (not limited to patent 210 | issues), conditions are imposed on you (whether by court order, 211 | agreement or otherwise) that contradict the conditions of this 212 | License, they do not excuse you from the conditions of this License. 213 | If you cannot distribute so as to satisfy simultaneously your 214 | obligations under this License and any other pertinent obligations, 215 | then as a consequence you may not distribute the Program at all. For 216 | example, if a patent license would not permit royalty-free 217 | redistribution of the Program by all those who receive copies directly 218 | or indirectly through you, then the only way you could satisfy both it 219 | and this License would be to refrain entirely from distribution of the 220 | Program. 221 | 222 | If any portion of this section is held invalid or unenforceable under 223 | any particular circumstance, the balance of the section is intended to 224 | apply and the section as a whole is intended to apply in other 225 | circumstances. 226 | 227 | It is not the purpose of this section to induce you to infringe any 228 | patents or other property right claims or to contest validity of any 229 | such claims; this section has the sole purpose of protecting the 230 | integrity of the free software distribution system, which is 231 | implemented by public license practices. Many people have made 232 | generous contributions to the wide range of software distributed 233 | through that system in reliance on consistent application of that 234 | system; it is up to the author/donor to decide if he or she is willing 235 | to distribute software through any other system and a licensee cannot 236 | impose that choice. 237 | 238 | This section is intended to make thoroughly clear what is believed to 239 | be a consequence of the rest of this License. 240 | 241 | **8.** If the distribution and/or use of the Program is restricted in 242 | certain countries either by patents or by copyrighted interfaces, the 243 | original copyright holder who places the Program under this License 244 | may add an explicit geographical distribution limitation excluding 245 | those countries, so that distribution is permitted only in or among 246 | countries not thus excluded. In such case, this License incorporates 247 | the limitation as if written in the body of this License. 248 | 249 | **9.** The Free Software Foundation may publish revised and/or new 250 | versions of the General Public License from time to time. Such new 251 | versions will be similar in spirit to the present version, but may 252 | differ in detail to address new problems or concerns. 253 | 254 | Each version is given a distinguishing version number. If the Program 255 | specifies a version number of this License which applies to it and 256 | "any later version", you have the option of following the terms and 257 | conditions either of that version or of any later version published by 258 | the Free Software Foundation. If the Program does not specify a 259 | version number of this License, you may choose any version ever 260 | published by the Free Software Foundation. 261 | 262 | **10.** If you wish to incorporate parts of the Program into other 263 | free programs whose distribution conditions are different, write to 264 | the author to ask for permission. For software which is copyrighted by 265 | the Free Software Foundation, write to the Free Software Foundation; 266 | we sometimes make exceptions for this. Our decision will be guided by 267 | the two goals of preserving the free status of all derivatives of our 268 | free software and of promoting the sharing and reuse of software 269 | generally. 270 | 271 | **NO WARRANTY** 272 | 273 | **11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO 274 | WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 275 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 276 | OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY 277 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 278 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 279 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 280 | PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 281 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 282 | 283 | **12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 284 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 285 | AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU 286 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 287 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 288 | PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 289 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 290 | FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF 291 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 292 | DAMAGES. 293 | 294 | ### END OF TERMS AND CONDITIONS 295 | 296 | ### How to Apply These Terms to Your New Programs 297 | 298 | If you develop a new program, and you want it to be of the greatest 299 | possible use to the public, the best way to achieve this is to make it 300 | free software which everyone can redistribute and change under these 301 | terms. 302 | 303 | To do so, attach the following notices to the program. It is safest to 304 | attach them to the start of each source file to most effectively 305 | convey the exclusion of warranty; and each file should have at least 306 | the "copyright" line and a pointer to where the full notice is found. 307 | 308 | one line to give the program's name and an idea of what it does. 309 | Copyright (C) yyyy name of author 310 | 311 | This program is free software; you can redistribute it and/or 312 | modify it under the terms of the GNU General Public License 313 | as published by the Free Software Foundation; either version 2 314 | of the License, or (at your option) any later version. 315 | 316 | This program is distributed in the hope that it will be useful, 317 | but WITHOUT ANY WARRANTY; without even the implied warranty of 318 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 319 | GNU General Public License for more details. 320 | 321 | You should have received a copy of the GNU General Public License 322 | along with this program; if not, write to the Free Software 323 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 324 | 325 | Also add information on how to contact you by electronic and paper 326 | mail. 327 | 328 | If the program is interactive, make it output a short notice like this 329 | when it starts in an interactive mode: 330 | 331 | Gnomovision version 69, Copyright (C) year name of author 332 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details 333 | type `show w'. This is free software, and you are welcome 334 | to redistribute it under certain conditions; type `show c' 335 | for details. 336 | 337 | The hypothetical commands \`show w' and \`show c' should show the 338 | appropriate parts of the General Public License. Of course, the 339 | commands you use may be called something other than \`show w' and 340 | \`show c'; they could even be mouse-clicks or menu items--whatever 341 | suits your program. 342 | 343 | You should also get your employer (if you work as a programmer) or 344 | your school, if any, to sign a "copyright disclaimer" for the program, 345 | if necessary. Here is a sample; alter the names: 346 | 347 | Yoyodyne, Inc., hereby disclaims all copyright 348 | interest in the program `Gnomovision' 349 | (which makes passes at compilers) written 350 | by James Hacker. 351 | 352 | signature of Ty Coon, 1 April 1989 353 | Ty Coon, President of Vice 354 | 355 | This General Public License does not permit incorporating your program 356 | into proprietary programs. If your program is a subroutine library, 357 | you may consider it more useful to permit linking proprietary 358 | applications with the library. If this is what you want to do, use the 359 | [GNU Lesser General Public 360 | License](https://www.gnu.org/licenses/lgpl.html) instead of this 361 | License. 362 | --------------------------------------------------------------------------------