├── circle.yml ├── .npmignore ├── .babelrc ├── .gitignore ├── README.md ├── CHANGELOG.md ├── src ├── tokenize.es6 └── index.es6 ├── package.json ├── test └── test.jsx └── LICENSE.md /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | node: 3 | version: 5.11.1 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | /npm-debug.log* 3 | .DS_Store 4 | .idea/ 5 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "react", 4 | "es2015" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /npm-debug.log* 3 | .DS_Store 4 | lib/ 5 | .idea/ 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEPRECATED 2 | 3 | This package is deprecated. It has been moved to [a new repo](https://github.com/Automattic/wp-calypso/tree/trunk/packages/interpolate-components) and renamed as `@automattic/interpolate-components`. `@automattic/interpolate-components@1.1.2` is a drop-in replacement for `interpolate-components@1.1.1`. 4 | 5 | [Original README](https://github.com/Automattic/wp-calypso/blob/2e3ecfac85750e0c3ca223f3eeb3a9731efb7c6d/packages/interpolate-components/README.md) 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.1.1 4 | * Drop deprecated React.createClass, React.DOM from test 5 | * Bump to allow for React ^16.0.0 6 | 7 | ## 1.1.0 8 | * Update to Babel 6 and bump node testing version to 5.11.1 9 | 10 | ## 1.0.5 11 | 12 | * Bump to allow for React ^15.1.0, still supporting ^0.14.3 13 | 14 | ## 1.0.4 15 | 16 | * Readme and package description edits. 17 | 18 | ## 1.0.3 19 | 20 | * Add changelog and tweak readme. 21 | 22 | ## 1.0.2 23 | 24 | * Main file should pull from the generated lib folder. 25 | 26 | ## 1.0.1 27 | 28 | * Separate project into src and lib folders to enable transpilation on npm publish. 29 | 30 | ## 1.0.0 31 | 32 | * Initial version, breaking module out of [wp-calypso](https://github.com/Automattic/wp-calypso). 33 | -------------------------------------------------------------------------------- /src/tokenize.es6: -------------------------------------------------------------------------------- 1 | function identifyToken( item ) { 2 | // {{/example}} 3 | if ( item.match( /^\{\{\// ) ) { 4 | return { 5 | type: 'componentClose', 6 | value: item.replace( /\W/g, '' ) 7 | }; 8 | } 9 | // {{example /}} 10 | if ( item.match( /\/\}\}$/ ) ) { 11 | return { 12 | type: 'componentSelfClosing', 13 | value: item.replace( /\W/g, '' ) 14 | }; 15 | } 16 | // {{example}} 17 | if ( item.match( /^\{\{/ ) ) { 18 | return { 19 | type: 'componentOpen', 20 | value: item.replace( /\W/g, '' ) 21 | }; 22 | } 23 | return { 24 | type: 'string', 25 | value: item 26 | }; 27 | } 28 | 29 | module.exports = function( mixedString ) { 30 | const tokenStrings = mixedString.split( /(\{\{\/?\s*\w+\s*\/?\}\})/g ); // split to components and strings 31 | return tokenStrings.map( identifyToken ); 32 | }; 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "interpolate-components", 3 | "version": "1.1.1", 4 | "description": "Convert strings into structured React components.", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/Automattic/interpolate-components.git" 8 | }, 9 | "main": "lib/index.js", 10 | "keywords": [ 11 | "react", 12 | "react-component", 13 | "interpolation" 14 | ], 15 | "scripts": { 16 | "compile": "babel -sd lib/ src/", 17 | "prepublish": "npm run compile", 18 | "test": "mocha --require babel-register --reporter spec test/test.jsx" 19 | }, 20 | "devDependencies": { 21 | "babel-cli": "^6.9.0", 22 | "babel-core": "^6.9.1", 23 | "babel-preset-es2015": "^6.9.0", 24 | "babel-preset-react": "^6.5.0", 25 | "babel-register": "^6.9.0", 26 | "mocha": "^2.3.4" 27 | }, 28 | "bugs": { 29 | "url": "https://github.com/Automattic/interpolate-components/issues" 30 | }, 31 | "homepage": "https://github.com/Automattic/interpolate-components#readme", 32 | "directories": { 33 | "test": "test" 34 | }, 35 | "dependencies": { 36 | "react": "^0.14.3 || ^15.1.0 || ^16.0.0", 37 | "react-addons-create-fragment": "^0.14.3 || ^15.1.0", 38 | "react-dom": "^0.14.3 || ^15.1.0 || ^16.0.0" 39 | }, 40 | "author": "Bob Ralian (http://github.com/rralian)", 41 | "license": "GPL-2.0" 42 | } 43 | -------------------------------------------------------------------------------- /src/index.es6: -------------------------------------------------------------------------------- 1 | /** 2 | * External Dependencies 3 | */ 4 | import React from 'react'; 5 | import createFragment from 'react-addons-create-fragment'; 6 | 7 | /** 8 | * Internal Dependencies 9 | */ 10 | import tokenize from './tokenize'; 11 | 12 | let currentMixedString; 13 | 14 | function getCloseIndex( openIndex, tokens ) { 15 | var openToken = tokens[ openIndex ], 16 | nestLevel = 0, 17 | token, i; 18 | for ( i = openIndex + 1; i < tokens.length; i++ ) { 19 | token = tokens[ i ]; 20 | if ( token.value === openToken.value ) { 21 | if ( token.type === 'componentOpen' ) { 22 | nestLevel++; 23 | continue; 24 | } 25 | if ( token.type === 'componentClose' ) { 26 | if ( nestLevel === 0 ) { 27 | return i; 28 | } 29 | nestLevel--; 30 | } 31 | } 32 | } 33 | // if we get this far, there was no matching close token 34 | throw new Error( 'Missing closing component token `' + openToken.value + '`' ); 35 | } 36 | 37 | function buildChildren( tokens, components ) { 38 | var children = [], 39 | childrenObject = {}, 40 | openComponent, clonedOpenComponent, openIndex, closeIndex, token, i, grandChildTokens, grandChildren, siblingTokens, siblings; 41 | 42 | for ( i = 0; i < tokens.length; i++ ) { 43 | token = tokens[ i ]; 44 | if ( token.type === 'string' ) { 45 | children.push( token.value ); 46 | continue; 47 | } 48 | // component node should at least be set 49 | if ( ! components.hasOwnProperty( token.value ) || typeof components[ token.value ] === 'undefined' ) { 50 | throw new Error( 'Invalid interpolation, missing component node: `' + token.value + '`' ); 51 | } 52 | // should be either ReactElement or null (both type "object"), all other types deprecated 53 | if ( typeof components[ token.value ] !== 'object' ) { 54 | throw new Error( 'Invalid interpolation, component node must be a ReactElement or null: `' + token.value + '`', '\n> ' + currentMixedString ); 55 | } 56 | // we should never see a componentClose token in this loop 57 | if ( token.type === 'componentClose' ) { 58 | throw new Error( 'Missing opening component token: `' + token.value + '`' ); 59 | } 60 | if ( token.type === 'componentOpen' ) { 61 | openComponent = components[ token.value ]; 62 | openIndex = i; 63 | break; 64 | } 65 | // componentSelfClosing token 66 | children.push( components[ token.value ] ); 67 | continue; 68 | } 69 | 70 | if ( openComponent ) { 71 | closeIndex = getCloseIndex( openIndex, tokens ); 72 | grandChildTokens = tokens.slice( ( openIndex + 1 ), closeIndex ); 73 | grandChildren = buildChildren( grandChildTokens, components ); 74 | clonedOpenComponent = React.cloneElement( openComponent, {}, grandChildren ); 75 | children.push( clonedOpenComponent ); 76 | 77 | if ( closeIndex < tokens.length - 1 ) { 78 | siblingTokens = tokens.slice( closeIndex + 1 ); 79 | siblings = buildChildren( siblingTokens, components ); 80 | children = children.concat( siblings ); 81 | } 82 | } 83 | 84 | if ( children.length === 1 ) { 85 | return children[ 0 ]; 86 | } 87 | 88 | children.forEach( ( child, index ) => { 89 | if ( child ) { 90 | childrenObject[ `interpolation-child-${index}` ] = child; 91 | } 92 | } ); 93 | 94 | return createFragment( childrenObject ); 95 | } 96 | 97 | function interpolate( options ) { 98 | const { mixedString, components, throwErrors } = options; 99 | 100 | currentMixedString = mixedString; 101 | 102 | if ( ! components ) { 103 | return mixedString; 104 | } 105 | 106 | if ( typeof components !== 'object' ) { 107 | if ( throwErrors ) { 108 | throw new Error( `Interpolation Error: unable to process \`${ mixedString }\` because components is not an object` ); 109 | } 110 | 111 | return mixedString; 112 | } 113 | 114 | let tokens = tokenize( mixedString ); 115 | 116 | try { 117 | return buildChildren( tokens, components ); 118 | } catch ( error ) { 119 | if ( throwErrors ) { 120 | throw new Error( `Interpolation Error: unable to process \`${ mixedString }\` because of error \`${ error.message }\`` ); 121 | } 122 | 123 | return mixedString; 124 | } 125 | }; 126 | 127 | export default interpolate; 128 | -------------------------------------------------------------------------------- /test/test.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import assert from 'assert'; 5 | import ReactDomServer from 'react-dom/server'; 6 | import React from 'react'; 7 | 8 | /** 9 | * Internal dependencies 10 | */ 11 | import interpolateComponents from '../src/index'; 12 | 13 | describe( 'interpolate-components', () => { 14 | const input = ; 15 | const div =
; 16 | const link = ; 17 | const em = ; 18 | const CustomComponentClass = ( { children, intro } ) => ( 19 | { intro }{ children } 20 | ); 21 | 22 | describe( 'with default container', () => { 23 | it( 'should return a react object with a span container', () => { 24 | const expectedResultString = 'testtest'; 25 | const interpolatedResult = interpolateComponents( { 26 | mixedString: 'test{{input/}}test', 27 | components: { 28 | input: input 29 | } 30 | } ); 31 | const instance = { interpolatedResult }; 32 | assert.equal( expectedResultString, ReactDomServer.renderToStaticMarkup( instance ) ); 33 | } ); 34 | it( 'should allow whitespace in the component placeholder', () => { 35 | const expectedResultString = 'testtest'; 36 | const interpolatedResult = interpolateComponents( { 37 | mixedString: 'test{{ input /}}test', 38 | components: { 39 | input: input 40 | } 41 | } ); 42 | const instance = { interpolatedResult }; 43 | assert.equal( expectedResultString, ReactDomServer.renderToStaticMarkup( instance ) ); 44 | } ); 45 | it( 'should not add extra span nodes if component is at end of string', () => { 46 | const expectedResultString = 'test'; 47 | const interpolatedResult = interpolateComponents( { 48 | mixedString: 'test{{ input /}}', 49 | components: { 50 | input: input 51 | } 52 | } ); 53 | const instance = { interpolatedResult }; 54 | assert.equal( expectedResultString, ReactDomServer.renderToStaticMarkup( instance ) ); 55 | } ); 56 | it( 'should not throw when component node is null', () => { 57 | assert.doesNotThrow( () => { 58 | interpolateComponents( { 59 | mixedString: 'test{{input/}}test', 60 | components: { 61 | input: null 62 | }, 63 | throwErrors: true 64 | } ); 65 | } ); 66 | } ); 67 | it( 'should not throw when component node is not an object', () => { 68 | assert.doesNotThrow( () => { 69 | interpolateComponents( { 70 | mixedString: 'test{{input/}}test{{input2/}}', 71 | components: { 72 | input: 'string', 73 | input2: 123 74 | }, 75 | } ); 76 | } ); 77 | } ); 78 | it( 'should return original string when component node is not an object', () => { 79 | const expectedResultString = 'test{{input/}}test{{input2/}}'; 80 | const interpolatedResult = interpolateComponents( { 81 | mixedString: 'test{{input/}}test{{input2/}}', 82 | components: { 83 | input: 'string', 84 | input2: 123 85 | } 86 | } ); 87 | const instance = { interpolatedResult }; 88 | assert.equal( expectedResultString, ReactDomServer.renderToStaticMarkup( instance ) ); 89 | } ); 90 | 91 | describe( 'when allowing thrown errors', () => { 92 | it( 'should throw when component node is not set', () => { 93 | assert.throws( () => { 94 | interpolateComponents( { 95 | mixedString: 'test{{input/}}', 96 | components: { 97 | mismatch: true 98 | }, 99 | throwErrors: true 100 | } ); 101 | } ); 102 | } ); 103 | it( 'should throw when component node is undefined', () => { 104 | assert.throws( () => { 105 | interpolateComponents( { 106 | mixedString: 'test{{input/}}', 107 | components: { 108 | input: undefined 109 | }, 110 | throwErrors: true 111 | } ); 112 | } ); 113 | } ); 114 | it( 'should throw error on invalid cross-nesting', () => { 115 | assert.throws( () => { 116 | interpolateComponents( { 117 | mixedString: '{{link}}a{{em}}b{{/link}}c{{/em}}', 118 | components: { 119 | link: link, 120 | em: em 121 | }, 122 | throwErrors: true 123 | } ); 124 | } ); 125 | } ); 126 | it( 'should throw when component is unclosed', () => { 127 | assert.throws( () => { 128 | interpolateComponents( { 129 | mixedString: '{{link}}test', 130 | components: { 131 | link: link 132 | }, 133 | throwErrors: true 134 | } ); 135 | } ); 136 | } ); 137 | } ); 138 | 139 | describe( 'when not allowing thrown errors', () => { 140 | it( 'should return original string when component node is not set', () => { 141 | const mixedString = 'test{{input/}}'; 142 | const results = interpolateComponents( { 143 | mixedString: mixedString, 144 | components: { 145 | mismatch: true 146 | } 147 | } ); 148 | assert.equal( mixedString, results ); 149 | } ); 150 | it( 'should return original string when component node is undefined', () => { 151 | const mixedString = 'test{{input/}}'; 152 | const results = interpolateComponents( { 153 | mixedString: mixedString, 154 | components: { 155 | input: undefined 156 | } 157 | } ); 158 | assert.equal( mixedString, results ); 159 | } ); 160 | it( 'should return original string on invalid cross-nesting', () => { 161 | const mixedString = '{{link}}a{{em}}b{{/link}}c{{/em}}'; 162 | const results = interpolateComponents( { 163 | mixedString: mixedString, 164 | components: { 165 | link: link, 166 | em: em 167 | } 168 | } ); 169 | assert.equal( mixedString, results ); 170 | } ); 171 | it( 'should return original string when component is unclosed', () => { 172 | const mixedString = '{{link}}test'; 173 | const results = interpolateComponents( { 174 | mixedString: mixedString, 175 | components: { 176 | link: link 177 | } 178 | } ); 179 | assert.equal( mixedString, results ); 180 | } ); 181 | } ); 182 | } ); 183 | 184 | describe( 'with components that wrap content', () => { 185 | it( 'should wrap the component around the inner contents', () => { 186 | const expectedResultString = 'test link content test'; 187 | const interpolatedComponent = interpolateComponents( { 188 | mixedString: 'test {{link}}link content{{/link}} test', 189 | components: { 190 | link: link 191 | } 192 | } ); 193 | const instance = { interpolatedComponent }; 194 | 195 | assert.equal( expectedResultString, ReactDomServer.renderToStaticMarkup( instance ) ); 196 | } ); 197 | it( 'should handle multiple wrapping components', () => { 198 | const expectedResultString = 'test link content link content2 test'; 199 | const interpolatedComponent = interpolateComponents( { 200 | mixedString: 'test {{link}}link content{{/link}} {{em}}link content2{{/em}} test', 201 | components: { 202 | link: link, 203 | em: em 204 | } 205 | } ); 206 | const instance = { interpolatedComponent }; 207 | assert.equal( expectedResultString, ReactDomServer.renderToStaticMarkup( instance ) ); 208 | } ); 209 | it( 'should handle nested wrapping components', () => { 210 | const expectedResultString = 'test link content emphasis test'; 211 | const interpolatedComponent = interpolateComponents( { 212 | mixedString: 'test {{link}}link content {{em}}emphasis{{/em}}{{/link}} test', 213 | components: { 214 | link: link, 215 | em: em 216 | } 217 | } ); 218 | const instance = { interpolatedComponent }; 219 | assert.equal( expectedResultString, ReactDomServer.renderToStaticMarkup( instance ) ); 220 | } ); 221 | it( 'should work with custom components', () => { 222 | const expectedResultString = 'here is: baba Hey!willie'; 223 | const interpolatedComponent = interpolateComponents( { 224 | mixedString: 'here is: {{x}}baba {{y}}willie{{/y}}{{/x}}', 225 | components: { 226 | x: , 227 | y: 228 | } 229 | } ); 230 | const instance = { interpolatedComponent }; 231 | assert.equal( expectedResultString, ReactDomServer.renderToStaticMarkup( instance ) ); 232 | } ); 233 | it( 'should allow repeated component tokens', () => { 234 | const expectedResultString = 'babadyado'; 235 | const interpolatedComponent = interpolateComponents( { 236 | mixedString: '{{link}}baba{{/link}}{{link}}dyado{{/link}}', 237 | components: { 238 | link: link 239 | } 240 | } ); 241 | const instance = { interpolatedComponent }; 242 | assert.equal( expectedResultString, ReactDomServer.renderToStaticMarkup( instance ) ); 243 | } ); 244 | it( 'should allow wrapping repeated components', () => { 245 | const expectedResultString = '
baba
dyado
'; 246 | const interpolatedComponent = interpolateComponents( { 247 | mixedString: '{{div}}baba{{div}}dyado{{/div}}{{/div}}', 248 | components: { 249 | div: div 250 | } 251 | } ); 252 | const instance = { interpolatedComponent }; 253 | assert.equal( expectedResultString, ReactDomServer.renderToStaticMarkup( instance ) ); 254 | } ); 255 | } ); 256 | } ); 257 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The GNU General Public License, Version 2, June 1991 (GPLv2) 2 | ============================================================ 3 | 4 | > Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | > 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 6 | 7 | Everyone is permitted to copy and distribute verbatim copies of this license 8 | document, but changing it is not allowed. 9 | 10 | 11 | Preamble 12 | -------- 13 | 14 | The licenses for most software are designed to take away your freedom to share 15 | and change it. By contrast, the GNU General Public License is intended to 16 | guarantee your freedom to share and change free software--to make sure the 17 | software is free for all its users. This General Public License applies to most 18 | of the Free Software Foundation's software and to any other program whose 19 | authors commit to using it. (Some other Free Software Foundation software is 20 | covered by the GNU Library 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 price. Our 24 | General Public Licenses are designed to make sure that you have the freedom to 25 | distribute copies of free software (and charge for this service if you wish), 26 | that you receive source code or can get it if you want it, that you can change 27 | the software or use pieces of it in new free programs; and that you know you can 28 | do these things. 29 | 30 | To protect your rights, we need to make restrictions that forbid anyone to deny 31 | you these rights or to ask you to surrender the rights. These restrictions 32 | translate to certain responsibilities for you if you distribute copies of the 33 | software, or if you modify it. 34 | 35 | For example, if you distribute copies of such a program, whether gratis or for a 36 | fee, you must give the recipients all the rights that you have. You must make 37 | sure that they, too, receive or can get the source code. And you must show them 38 | these terms so they know their rights. 39 | 40 | We protect your rights with two steps: (1) copyright the software, and (2) offer 41 | you this license which gives you legal permission to copy, distribute and/or 42 | modify the software. 43 | 44 | Also, for each author's protection and ours, we want to make certain that 45 | everyone understands that there is no warranty for this free software. If the 46 | software is modified by someone else and passed on, we want its recipients to 47 | know that what they have is not the original, so that any problems introduced by 48 | others will not reflect on the original authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software patents. We wish 51 | to avoid the danger that redistributors of a free program will individually 52 | obtain patent licenses, in effect making the program proprietary. To prevent 53 | this, we have made it clear that any patent must be licensed for everyone's free 54 | use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and modification 57 | follow. 58 | 59 | 60 | Terms And Conditions For Copying, Distribution And Modification 61 | --------------------------------------------------------------- 62 | 63 | **0.** This License applies to any program or other work which contains a notice 64 | placed by the copyright holder saying it may be distributed under the terms of 65 | this General Public License. The "Program", below, refers to any such program or 66 | work, and a "work based on the Program" means either the Program or any 67 | derivative work under copyright law: that is to say, a work containing the 68 | Program or a portion of it, either verbatim or with modifications and/or 69 | translated into another language. (Hereinafter, translation is included without 70 | limitation in the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not covered by 73 | this License; they are outside its scope. The act of running the Program is not 74 | restricted, and the output from the Program is covered only if its contents 75 | constitute a work based on the Program (independent of having been made by 76 | running the Program). Whether that is true depends on what the Program does. 77 | 78 | **1.** You may copy and distribute verbatim copies of the Program's source code 79 | as you receive it, in any medium, provided that you conspicuously and 80 | appropriately publish on each copy an appropriate copyright notice and 81 | disclaimer of warranty; keep intact all the notices that refer to this License 82 | and to the absence of any warranty; and give any other recipients of the Program 83 | a copy of this License along with the Program. 84 | 85 | You may charge a fee for the physical act of transferring a copy, and you may at 86 | your option offer warranty protection in exchange for a fee. 87 | 88 | **2.** You may modify your copy or copies of the Program or any portion of it, 89 | thus forming a work based on the Program, and copy and distribute such 90 | modifications or work under the terms of Section 1 above, provided that you also 91 | meet all of these conditions: 92 | 93 | * **a)** You must cause the modified files to carry prominent notices stating 94 | that you changed the files and the date of any change. 95 | 96 | * **b)** You must cause any work that you distribute or publish, that in whole 97 | or in part contains or is derived from the Program or any part thereof, to 98 | be licensed as a whole at no charge to all third parties under the terms of 99 | this License. 100 | 101 | * **c)** If the modified program normally reads commands interactively when 102 | run, you must cause it, when started running for such interactive use in the 103 | most ordinary way, to print or display an announcement including an 104 | appropriate copyright notice and a notice that there is no warranty (or 105 | else, saying that you provide a warranty) and that users may redistribute 106 | the program under these conditions, and telling the user how to view a copy 107 | of this License. (Exception: if the Program itself is interactive but does 108 | not normally print such an announcement, your work based on the Program is 109 | not required to print an announcement.) 110 | 111 | These requirements apply to the modified work as a whole. If identifiable 112 | sections of that work are not derived from the Program, and can be reasonably 113 | considered independent and separate works in themselves, then this License, and 114 | its terms, do not apply to those sections when you distribute them as separate 115 | works. But when you distribute the same sections as part of a whole which is a 116 | work based on the Program, the distribution of the whole must be on the terms of 117 | this License, whose permissions for other licensees extend to the entire whole, 118 | and thus to each and every part regardless of who wrote it. 119 | 120 | Thus, it is not the intent of this section to claim rights or contest your 121 | rights to work written entirely by you; rather, the intent is to exercise the 122 | right to control the distribution of derivative or collective works based on the 123 | Program. 124 | 125 | In addition, mere aggregation of another work not based on the Program with the 126 | Program (or with a work based on the Program) on a volume of a storage or 127 | distribution medium does not bring the other work under the scope of this 128 | License. 129 | 130 | **3.** You may copy and distribute the Program (or a work based on it, under 131 | Section 2) in object code or executable form under the terms of Sections 1 and 2 132 | above provided that you also do one of the following: 133 | 134 | * **a)** Accompany it with the complete corresponding machine-readable source 135 | code, which must be distributed under the terms of Sections 1 and 2 above on 136 | a medium customarily used for software interchange; or, 137 | 138 | * **b)** Accompany it with a written offer, valid for at least three years, to 139 | give any third party, for a charge no more than your cost of physically 140 | performing source distribution, a complete machine-readable copy of the 141 | corresponding source code, to be distributed under the terms of Sections 1 142 | and 2 above on a medium customarily used for software interchange; or, 143 | 144 | * **c)** Accompany it with the information you received as to the offer to 145 | distribute corresponding source code. (This alternative is allowed only for 146 | noncommercial distribution and only if you received the program in object 147 | code or executable form with such an offer, in accord with Subsection b 148 | above.) 149 | 150 | The source code for a work means the preferred form of the work for making 151 | modifications to it. For an executable work, complete source code means all the 152 | source code for all modules it contains, plus any associated interface 153 | definition files, plus the scripts used to control compilation and installation 154 | of the executable. However, as a special exception, the source code distributed 155 | need not include anything that is normally distributed (in either source or 156 | binary form) with the major components (compiler, kernel, and so on) of the 157 | operating system on which the executable runs, unless that component itself 158 | accompanies the executable. 159 | 160 | If distribution of executable or object code is made by offering access to copy 161 | from a designated place, then offering equivalent access to copy the source code 162 | from the same place counts as distribution of the source code, even though third 163 | parties are not compelled to copy the source along with the object code. 164 | 165 | **4.** You may not copy, modify, sublicense, or distribute the Program except as 166 | expressly provided under this License. Any attempt otherwise to copy, modify, 167 | sublicense or distribute the Program is void, and will automatically terminate 168 | your rights under this License. However, parties who have received copies, or 169 | rights, from you under this License will not have their licenses terminated so 170 | long as such parties remain in full compliance. 171 | 172 | **5.** You are not required to accept this License, since you have not signed 173 | it. However, nothing else grants you permission to modify or distribute the 174 | Program or its derivative works. These actions are prohibited by law if you do 175 | not accept this License. Therefore, by modifying or distributing the Program (or 176 | any work based on the Program), you indicate your acceptance of this License to 177 | do so, and all its terms and conditions for copying, distributing or modifying 178 | the Program or works based on it. 179 | 180 | **6.** Each time you redistribute the Program (or any work based on the 181 | Program), the recipient automatically receives a license from the original 182 | licensor to copy, distribute or modify the Program subject to these terms and 183 | conditions. You may not impose any further restrictions on the recipients' 184 | exercise of the rights granted herein. You are not responsible for enforcing 185 | compliance by third parties to this License. 186 | 187 | **7.** If, as a consequence of a court judgment or allegation of patent 188 | infringement or for any other reason (not limited to patent issues), conditions 189 | are imposed on you (whether by court order, agreement or otherwise) that 190 | contradict the conditions of this License, they do not excuse you from the 191 | conditions of this License. If you cannot distribute so as to satisfy 192 | simultaneously your obligations under this License and any other pertinent 193 | obligations, then as a consequence you may not distribute the Program at all. 194 | For example, if a patent license would not permit royalty-free redistribution of 195 | the Program by all those who receive copies directly or indirectly through you, 196 | then the only way you could satisfy both it and this License would be to refrain 197 | entirely from distribution of the Program. 198 | 199 | If any portion of this section is held invalid or unenforceable under any 200 | particular circumstance, the balance of the section is intended to apply and the 201 | section as a whole is intended to apply in other circumstances. 202 | 203 | It is not the purpose of this section to induce you to infringe any patents or 204 | other property right claims or to contest validity of any such claims; this 205 | section has the sole purpose of protecting the integrity of the free software 206 | distribution system, which is implemented by public license practices. Many 207 | people have made generous contributions to the wide range of software 208 | distributed through that system in reliance on consistent application of that 209 | system; it is up to the author/donor to decide if he or she is willing to 210 | distribute software through any other system and a licensee cannot impose that 211 | choice. 212 | 213 | This section is intended to make thoroughly clear what is believed to be a 214 | consequence of the rest of this License. 215 | 216 | **8.** If the distribution and/or use of the Program is restricted in certain 217 | countries either by patents or by copyrighted interfaces, the original copyright 218 | holder who places the Program under this License may add an explicit 219 | geographical distribution limitation excluding those countries, so that 220 | distribution is permitted only in or among countries not thus excluded. In such 221 | case, this License incorporates the limitation as if written in the body of this 222 | License. 223 | 224 | **9.** The Free Software Foundation may publish revised and/or new versions of 225 | the General Public License from time to time. Such new versions will be similar 226 | in spirit to the present version, but may differ in detail to address new 227 | problems or concerns. 228 | 229 | Each version is given a distinguishing version number. If the Program specifies 230 | a version number of this License which applies to it and "any later version", 231 | you have the option of following the terms and conditions either of that version 232 | or of any later version published by the Free Software Foundation. If the 233 | Program does not specify a version number of this License, you may choose any 234 | version ever published by the Free Software Foundation. 235 | 236 | **10.** If you wish to incorporate parts of the Program into other free programs 237 | whose distribution conditions are different, write to the author to ask for 238 | permission. For software which is copyrighted by the Free Software Foundation, 239 | write to the Free Software Foundation; we sometimes make exceptions for this. 240 | Our decision will be guided by the two goals of preserving the free status of 241 | all derivatives of our free software and of promoting the sharing and reuse of 242 | software generally. 243 | 244 | 245 | No Warranty 246 | ----------- 247 | 248 | **11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR 249 | THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE 250 | STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM 251 | "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 252 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 253 | PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 254 | PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 255 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 256 | 257 | **12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 258 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 259 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 260 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR 261 | INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA 262 | BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 263 | FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER 264 | OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 265 | --------------------------------------------------------------------------------