├── MANIFEST.in ├── requirements.txt ├── tree_format ├── tests │ ├── __init__.py │ └── test_text.py ├── __init__.py └── _text.py ├── tox.ini ├── .travis.yml ├── README.md ├── setup.py └── LICENSE /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | testtools 2 | -------------------------------------------------------------------------------- /tree_format/tests/__init__.py: -------------------------------------------------------------------------------- 1 | """Tests for tree_format.""" 2 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py27, py34, py35, pep8 3 | 4 | [testenv] 5 | deps = -e.[dev] 6 | commands = 7 | {envpython} setup.py --version 8 | {envpython} -m unittest discover tree_format.tests 9 | 10 | [testenv:py27] 11 | basepython = python2.7 12 | deps = 13 | {[testenv]deps} 14 | 15 | [testenv:py34] 16 | basepython = python3.4 17 | deps = 18 | {[testenv]deps} 19 | 20 | [testenv:py35] 21 | basepython = python3.5 22 | deps = 23 | {[testenv]deps} 24 | 25 | [testenv:pep8] 26 | deps = pep8 27 | basepython = python2.7 28 | commands = pep8 tree_format 29 | -------------------------------------------------------------------------------- /tree_format/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2015 Jonathan M. Lange 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Nicely format trees.""" 16 | 17 | from ._text import ( 18 | format_ascii_tree, 19 | format_tree, 20 | print_tree, 21 | ) 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 2.7 3 | sudo: false 4 | cache: 5 | directories: 6 | - $HOME/.cache/pip 7 | branches: 8 | only: 9 | - master 10 | 11 | env: 12 | - TOX_ENV=py27 13 | - TOX_ENV=py34 14 | #- TOX_ENV=py35 15 | - TOX_ENV=pep8 16 | 17 | # Hack until is resolved. 18 | matrix: 19 | include: 20 | - python: 3.5 21 | env: 22 | - TOX_ENV=py35 23 | 24 | install: 25 | - pip install coveralls coverage tox 26 | - python setup.py --version 27 | - pip install -e.[dev] 28 | 29 | script: 30 | - coverage run --branch --source tree_format $(type -p py.test) tree_format 31 | - coverage report -m 32 | - tox -e "${TOX_ENV}" 33 | 34 | after_success: 35 | - coveralls 36 | 37 | notifications: 38 | email: false 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Python library to generate nicely formatted trees, like the UNIX `tree` 2 | command. 3 | 4 | ## Example 5 | 6 | Produce output like this: 7 | 8 | ``` 9 | foo 10 | ├── bar 11 | │ ├── a 12 | │ └── b 13 | ├── baz 14 | └── qux 15 | └── c⏎ 16 | d 17 | ``` 18 | 19 | using code like this: 20 | 21 | ```python 22 | from operator import itemgetter 23 | 24 | from tree_format import format_tree 25 | 26 | tree = ( 27 | 'foo', [ 28 | ('bar', [ 29 | ('a', []), 30 | ('b', []), 31 | ]), 32 | ('baz', []), 33 | ('qux', [ 34 | ('c\nd', []), 35 | ]), 36 | ], 37 | ) 38 | 39 | print format_tree( 40 | tree, format_node=itemgetter(0), get_children=itemgetter(1)) 41 | ``` 42 | 43 | ## License 44 | 45 | This is made available under the Apache Software License, version 2.0. 46 | 47 | Copyright (c) 2015 - Jonathan M. Lange 48 | 49 | ## Testing 50 | 51 | Run tests with: 52 | 53 | ``` 54 | python -m testtools.run discover 55 | ``` 56 | 57 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (c) 2016 Jonathan M. Lange 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | import codecs 18 | import os 19 | 20 | from setuptools import find_packages, setup 21 | 22 | 23 | readme_path = os.path.join(os.path.dirname(__file__), "README.md") 24 | with codecs.open(readme_path, encoding='utf-8', errors='replace') as readme: 25 | long_description = readme.read() 26 | 27 | classifiers = [ 28 | "Intended Audience :: Developers", 29 | "License :: OSI Approved :: Apache Software License", 30 | "License :: OSI Approved :: BSD License", 31 | "Operating System :: OS Independent", 32 | "Programming Language :: Python", 33 | "Programming Language :: Python :: 2", 34 | "Programming Language :: Python :: 2.7", 35 | "Programming Language :: Python :: Implementation :: CPython", 36 | "Programming Language :: Python :: Implementation :: PyPy", 37 | ] 38 | 39 | setup( 40 | name="tree-format", 41 | long_description=long_description, 42 | version="0.1.2", 43 | packages=find_packages(), 44 | author="Jonathan M. Lange", 45 | author_email="jml@mumak.net", 46 | classifiers=classifiers, 47 | url="http://github.com/jml/tree-format", 48 | extras_require={ 49 | "dev": ["pytest>=2.7.1", "testtools>=1.8.0"], 50 | }, 51 | ) 52 | -------------------------------------------------------------------------------- /tree_format/_text.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (c) 2015 Jonathan M. Lange 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | """Library for formatting trees.""" 19 | 20 | import itertools 21 | 22 | 23 | class Options(object): 24 | 25 | def __init__(self, 26 | FORK=u'\u251c', 27 | LAST=u'\u2514', 28 | VERTICAL=u'\u2502', 29 | HORIZONTAL=u'\u2500', 30 | NEWLINE=u'\u23ce'): 31 | self.FORK = FORK 32 | self.LAST = LAST 33 | self.VERTICAL = VERTICAL 34 | self.HORIZONTAL = HORIZONTAL 35 | self.NEWLINE = NEWLINE 36 | 37 | 38 | ASCII_OPTIONS = Options(FORK=u'|', 39 | LAST=u'+', 40 | VERTICAL=u'|', 41 | HORIZONTAL=u'-', 42 | NEWLINE=u'\n') 43 | 44 | 45 | def _format_newlines(prefix, formatted_node, options): 46 | """ 47 | Convert newlines into U+23EC characters, followed by an actual newline and 48 | then a tree prefix so as to position the remaining text under the previous 49 | line. 50 | """ 51 | replacement = u''.join([ 52 | options.NEWLINE, 53 | u'\n', 54 | prefix]) 55 | return formatted_node.replace(u'\n', replacement) 56 | 57 | 58 | def _format_tree(node, format_node, get_children, options, prefix=u''): 59 | children = list(get_children(node)) 60 | next_prefix = u''.join([prefix, options.VERTICAL, u' ']) 61 | for child in children[:-1]: 62 | yield u''.join([prefix, 63 | options.FORK, 64 | options.HORIZONTAL, 65 | options.HORIZONTAL, 66 | u' ', 67 | _format_newlines(next_prefix, 68 | format_node(child), 69 | options)]) 70 | for result in _format_tree(child, 71 | format_node, 72 | get_children, 73 | options, 74 | next_prefix): 75 | yield result 76 | if children: 77 | last_prefix = u''.join([prefix, u' ']) 78 | yield u''.join([prefix, 79 | options.LAST, 80 | options.HORIZONTAL, 81 | options.HORIZONTAL, 82 | u' ', 83 | _format_newlines(last_prefix, 84 | format_node(children[-1]), 85 | options)]) 86 | for result in _format_tree(children[-1], 87 | format_node, 88 | get_children, 89 | options, 90 | last_prefix): 91 | yield result 92 | 93 | 94 | def format_tree(node, format_node, get_children, options=None): 95 | lines = itertools.chain( 96 | [format_node(node)], 97 | _format_tree(node, format_node, get_children, options or Options()), 98 | [u''], 99 | ) 100 | return u'\n'.join(lines) 101 | 102 | 103 | def format_ascii_tree(tree, format_node, get_children): 104 | """ Formats the tree using only ascii characters """ 105 | return format_tree(tree, 106 | format_node, 107 | get_children, 108 | ASCII_OPTIONS) 109 | 110 | 111 | def print_tree(*args, **kwargs): 112 | print(format_tree(*args, **kwargs)) 113 | -------------------------------------------------------------------------------- /tree_format/tests/test_text.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (c) 2015 Jonathan M. Lange 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import doctest 18 | from operator import itemgetter 19 | from textwrap import dedent 20 | 21 | from testtools import TestCase 22 | from testtools.matchers import DocTestMatches 23 | 24 | from .._text import ( 25 | format_tree, format_ascii_tree, 26 | ) 27 | 28 | 29 | class TestFormatTree(TestCase): 30 | 31 | def format_tree(self, tree): 32 | return format_tree(tree, itemgetter(0), itemgetter(1)) 33 | 34 | def format_ascii_tree(self, tree): 35 | return format_ascii_tree(tree, itemgetter(0), itemgetter(1)) 36 | 37 | def test_single_node_tree(self): 38 | tree = ('foo', []) 39 | output = self.format_tree(tree) 40 | self.assertEqual(dedent(u'''\ 41 | foo 42 | '''), output) 43 | 44 | def test_single_level_tree(self): 45 | tree = ( 46 | 'foo', [ 47 | ('bar', []), 48 | ('baz', []), 49 | ('qux', []), 50 | ], 51 | ) 52 | output = self.format_tree(tree) 53 | self.assertEqual(dedent(u'''\ 54 | foo 55 | ├── bar 56 | ├── baz 57 | └── qux 58 | '''), output) 59 | 60 | def test_multi_level_tree(self): 61 | tree = ( 62 | 'foo', [ 63 | ('bar', [ 64 | ('a', []), 65 | ('b', []), 66 | ]), 67 | ('baz', []), 68 | ('qux', []), 69 | ], 70 | ) 71 | output = self.format_tree(tree) 72 | self.assertEqual(dedent(u'''\ 73 | foo 74 | ├── bar 75 | │ ├── a 76 | │ └── b 77 | ├── baz 78 | └── qux 79 | '''), output) 80 | 81 | def test_multi_level_on_last_node_tree(self): 82 | tree = ( 83 | 'foo', [ 84 | ('bar', []), 85 | ('baz', []), 86 | ('qux', [ 87 | ('a', []), 88 | ('b', []), 89 | ]), 90 | ], 91 | ) 92 | output = self.format_tree(tree) 93 | self.assertEqual(dedent(u'''\ 94 | foo 95 | ├── bar 96 | ├── baz 97 | └── qux 98 | ├── a 99 | └── b 100 | '''), output) 101 | 102 | def test_acceptance(self): 103 | output = self.format_tree(ACCEPTANCE_INPUT) 104 | self.assertThat( 105 | output, 106 | DocTestMatches( 107 | ACCEPTANCE_OUTPUT, 108 | doctest.ELLIPSIS | 109 | doctest.NORMALIZE_WHITESPACE | 110 | doctest.REPORT_NDIFF)) 111 | 112 | def test_newlines(self): 113 | tree = ( 114 | 'foo', [ 115 | ('bar\nfrob', [ 116 | ('a', []), 117 | ('b\nc\nd', []), 118 | ]), 119 | ('baz', []), 120 | ('qux\nfrab', []), 121 | ], 122 | ) 123 | output = self.format_tree(tree) 124 | self.assertEqual(dedent(u'''\ 125 | foo 126 | ├── bar⏎ 127 | │ frob 128 | │ ├── a 129 | │ └── b⏎ 130 | │ c⏎ 131 | │ d 132 | ├── baz 133 | └── qux⏎ 134 | frab 135 | '''), output) 136 | 137 | def test_ascii__tree(self): 138 | tree = ( 139 | 'foo', [ 140 | ('bar', [ 141 | ('a', []), 142 | ('b', []), 143 | ]), 144 | ('baz', []), 145 | ('qux', []), 146 | ], 147 | ) 148 | output = self.format_ascii_tree(tree) 149 | self.assertEqual(dedent(u'''\ 150 | foo 151 | |-- bar 152 | | |-- a 153 | | +-- b 154 | |-- baz 155 | +-- qux 156 | '''), output) 157 | 158 | 159 | def d(name, files): 160 | return (name, files) 161 | 162 | 163 | def f(name): 164 | return (name, []) 165 | 166 | 167 | ACCEPTANCE_INPUT = \ 168 | d(u'.', [ 169 | f(u'cabal.sandbox.config'), 170 | f(u'config.yaml'), 171 | d(u'dist', [ 172 | d(u'build', [ 173 | d(u'autogen', [ 174 | f(u'cabal_macros.h'), 175 | f(u'Paths_hodor.hs'), 176 | ]), 177 | d(u'hodor', [ 178 | f(u'hodor'), 179 | d(u'hodor-tmp', [ 180 | d(u'Hodor', map(f, [ 181 | u'Actions.hi', 182 | u'Actions.o', 183 | u'CommandLine.hi', 184 | u'CommandLine.o', 185 | u'Commands.hi', 186 | u'Commands.o', 187 | u'Config.hi', 188 | u'Config.o', 189 | u'File.hi', 190 | u'File.o', 191 | u'Format.hi', 192 | u'Format.o', 193 | u'Functional.hi', 194 | u'Functional.o', 195 | u'Parser.hi', 196 | u'Parser.o', 197 | u'Types.hi', 198 | u'Types.o', 199 | ])), 200 | f(u'Hodor.hi'), 201 | f(u'Hodor.o'), 202 | f(u'Main.hi'), 203 | f(u'Main.o'), 204 | ]), 205 | ]), 206 | ]), 207 | f(u'package.conf.inplace'), 208 | f(u'setup-config'), 209 | ]), 210 | d(u'Hodor', map(f, [ 211 | u'Actions.hs', 212 | u'CommandLine.hs', 213 | u'Commands.hs', 214 | u'Config.hs', 215 | u'File.hs', 216 | u'Format.hs', 217 | u'Functional.hs', 218 | u'Parser.hs', 219 | u'Reports.hs', 220 | u'Types.hs', 221 | ])), 222 | f(u'hodor.cabal'), 223 | f(u'Hodor.hs'), 224 | f(u'LICENSE'), 225 | f(u'Main.hs'), 226 | f(u'notes.md'), 227 | f(u'Setup.hs'), 228 | d(u'Tests', map(f, [ 229 | u'FormatSpec.hs', 230 | u'Generators.hs', 231 | u'ParserSpec.hs', 232 | u'TypesSpec.hs', 233 | ])), 234 | f(u'Tests.hs'), 235 | f(u'todo.txt'), 236 | ]) 237 | 238 | 239 | ACCEPTANCE_OUTPUT = u'''\ 240 | . 241 | ├── cabal.sandbox.config 242 | ├── config.yaml 243 | ├── dist 244 | │ ├── build 245 | │ │ ├── autogen 246 | │ │ │ ├── cabal_macros.h 247 | │ │ │ └── Paths_hodor.hs 248 | │ │ └── hodor 249 | │ │ ├── hodor 250 | │ │ └── hodor-tmp 251 | │ │ ├── Hodor 252 | │ │ │ ├── Actions.hi 253 | │ │ │ ├── Actions.o 254 | │ │ │ ├── CommandLine.hi 255 | │ │ │ ├── CommandLine.o 256 | │ │ │ ├── Commands.hi 257 | │ │ │ ├── Commands.o 258 | │ │ │ ├── Config.hi 259 | │ │ │ ├── Config.o 260 | │ │ │ ├── File.hi 261 | │ │ │ ├── File.o 262 | │ │ │ ├── Format.hi 263 | │ │ │ ├── Format.o 264 | │ │ │ ├── Functional.hi 265 | │ │ │ ├── Functional.o 266 | │ │ │ ├── Parser.hi 267 | │ │ │ ├── Parser.o 268 | │ │ │ ├── Types.hi 269 | │ │ │ └── Types.o 270 | │ │ ├── Hodor.hi 271 | │ │ ├── Hodor.o 272 | │ │ ├── Main.hi 273 | │ │ └── Main.o 274 | │ ├── package.conf.inplace 275 | │ └── setup-config 276 | ├── Hodor 277 | │ ├── Actions.hs 278 | │ ├── CommandLine.hs 279 | │ ├── Commands.hs 280 | │ ├── Config.hs 281 | │ ├── File.hs 282 | │ ├── Format.hs 283 | │ ├── Functional.hs 284 | │ ├── Parser.hs 285 | │ ├── Reports.hs 286 | │ └── Types.hs 287 | ├── hodor.cabal 288 | ├── Hodor.hs 289 | ├── LICENSE 290 | ├── Main.hs 291 | ├── notes.md 292 | ├── Setup.hs 293 | ├── Tests 294 | │ ├── FormatSpec.hs 295 | │ ├── Generators.hs 296 | │ ├── ParserSpec.hs 297 | │ └── TypesSpec.hs 298 | ├── Tests.hs 299 | └── todo.txt 300 | ''' 301 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | --------------------------------------------------------------------------------