├── train └── TRAINED_MODEL_HERE.md ├── README.md ├── README_EN.md ├── Piano2Midi.py ├── .gitignore └── LICENSE /train/TRAINED_MODEL_HERE.md: -------------------------------------------------------------------------------- 1 | # Download or Create Trained Model AND Place It Here 2 | 3 | You can download Model from [Here](https://github.com/tensorflow/magenta/tree/master/magenta/models/onsets_frames_transcription). -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Piano 2 Midi 2 | >If you want English README.md, Click [here](README_EN.md). 3 | ## 🎵Introduction 4 | Piano 2 Midi는 여러분의 피아노 연주를 듣고, 딥러닝을 통하여 이를 디지털 악보화 해주는 프로그램입니다! 5 | 6 | WAV 형식으로 녹음된 피아노 연주를 입력하면, 프로그램이 이를 MID 형식의 파일로 변환하여 같은 디렉토리에 출력해줍니다. 7 | 8 | ## 🎹How to use 9 | >현재 .exe 형태의 파일은 제공하지 않습니다. 10 | 11 | 1. 프로젝트를 다운로드합니다. 12 | 2. [여기](https://storage.googleapis.com/magentadata/models/onsets_frames_transcription/maestro_checkpoint.zip)를 클릭하여 미리 학습된 데이터셋 체크포인트를 다운로드하여, 프로젝트 폴더안에 압축을 풀어줍니다. 13 | 3. 아래 `pip` 명령어를 활용하여 필요한 라이브러리를 모두 설치합니다. 14 | ~~~ 15 | pip install --upgrade tensorflow 16 | pip install magenta 17 | ~~~ 18 | 4. `Piano2Midi.py` 를 실행하고, 잠시 기다리다가 파일을 입력하라는 안내가 나오면 파일 이름을 입력합니다. 19 | 5. 잠시 기다리면, 프로그램이 프로젝트 경로에 (파일이름).mid 형식으로 파일을 출력하고 종료됩니다. 20 | 21 | ## 🎼Magenta Library 22 | 이 프로그램은 [Tensorflow Magenta](https://github.com/tensorflow/magenta)의 [onsets_frames_transcription](https://github.com/tensorflow/magenta/tree/master/magenta/models/onsets_frames_transcription) 모델을 활용하여 제작되었습니다. 23 | 24 | 데이터셋은 역시 Magenta의 [Maestro](https://magenta.tensorflow.org/datasets/maestro)를 사용하였고, 이에 관련된 자세한 포스트는 [여기](https://magenta.tensorflow.org/maestro-wave2midi2wave)에서 확인할 수 있습니다. 25 | 26 | ## 📜License 27 | Magenta 라이브러리는 Apache License 2.0을 따르며, Maestro 데이터셋도 동일합니다. 28 | 29 | 또한 이 프로젝트도 Apache License 2.0을 적용하여 자유롭게 이용하실 수 있습니다. 30 | 31 | ## 📋Update Plan 32 | ### Midi 2 Piano 33 | Maestro 데이터셋을 활용해서 이번엔 midi를 wav 음악으로 연주해주는 딥러닝 프로그램을 만들어 볼 것. -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | 2 | # Piano 2 Midi 3 | >한국어 README.md 가 필요하신 분은, [여기](README.md)를 눌러주세요.. 4 | ## 🎵Introduction 5 | Piano 2 Midi is a program to covert your Piano music to Musical Instrument Digital Interface! 6 | 7 | When you give a piano performance recorded in WAV format, the program converts it to a file in MID format. 8 | 9 | ## 🎹How to use 10 | >Currently, There is no .exe file for this project. 11 | 12 | 1. Download the whole Project 13 | 2. Click [here](https://storage.googleapis.com/magentadata/models/onsets_frames_transcription/maestro_checkpoint.zip) to download pre-trained Data checkpoint, and unpack it in project directory 14 | 3. Use `pip` below to download tensorflow and magenta lib. 15 | ~~~ 16 | pip install --upgrade tensorflow 17 | pip install magenta 18 | ~~~ 19 | 4. Run `Piano2Midi.py` and wait for a while. And input your .wav file name that you want to convert. 20 | 5. Wait again. When program complete the converting, it will print a message to notice you. 21 | 22 | ## 🎼Magenta Library 23 | This program made with [Tensorflow Magenta](https://github.com/tensorflow/magenta)'s [onsets_frames_transcription](https://github.com/tensorflow/magenta/tree/master/magenta/models/onsets_frames_transcription) model. 24 | 25 | And used [Maestro](https://magenta.tensorflow.org/datasets/maestro) Dataset. You can find out some more information about this dataset from [here](https://magenta.tensorflow.org/maestro-wave2midi2wave). 26 | 27 | ## License 28 | Magenta is under Apache License 2.0, and Maestro dataset is same. 29 | 30 | And you can use this projects code under Apache License 2.0, same as magenta! 31 | 32 | ## Update Plan 33 | ### Midi 2 Piano 34 | Using Maestro Dataset, I will make midi to piano program next time. -------------------------------------------------------------------------------- /Piano2Midi.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import os 3 | 4 | from magenta.protobuf import music_pb2 5 | from magenta.music import sequences_lib, midi_io 6 | from magenta.models.onsets_frames_transcription import configs, data, train_util, audio_label_data_utils, constants 7 | 8 | # Trained Model Directory 9 | MODEL_DIR = './train' 10 | 11 | # Hyperparamter 12 | config = configs.CONFIG_MAP['onsets_frames'] 13 | hparams = config.hparams 14 | hparams.batch_size = 1 15 | hparams.use_cudnn = False 16 | hparams.audio_transform = False 17 | 18 | example = tf.placeholder(tf.string, [None]) 19 | 20 | # Logging 21 | tf.logging.info('model_dir=%s', MODEL_DIR) 22 | tf.logging.info('checkpoint_path=%s', 'checkpoint') 23 | 24 | # 배치 생성 25 | dataset = data.provide_batch(examples=example, preprocess_examples=True, 26 | params=hparams, is_training=False, shuffle_examples=False, 27 | skip_n_initial_records=0) 28 | 29 | # Estimator 30 | estimator = train_util.create_estimator(config.model_fn, MODEL_DIR, hparams) 31 | 32 | # 배치를 순환하는 이터레이터 33 | iterator =dataset.make_initializable_iterator() 34 | next_record = iterator.get_next() 35 | 36 | sess = tf.Session() 37 | 38 | #전역변수 및 로컬변수 초기화 39 | sess.run([tf.initializers.global_variables(), tf.initializers.local_variables()]) 40 | 41 | #tensor로부터 사용하려는 데이터를 불러와 Dataset 인스턴스 생성 42 | def input_fn(params): 43 | del params 44 | return tf.data.Dataset.from_tensors(sess.run(next_record)) 45 | 46 | def infer(filename): 47 | # WAV 파일 Binary로 읽기 48 | wav = open(filename,'rb') 49 | wav_data = wav.read() 50 | wav.close() 51 | 52 | tf.logging.info('User .WAV FIle %s length %s bytes', filename, len(wav_data)) 53 | 54 | ## 전처리 55 | # 청크로 분할 후, Protocol Buffers 로 변환 56 | to_process = [] 57 | examples = list(audio_label_data_utils.process_record(wav_data=wav_data, ns=music_pb2.NoteSequence(), 58 | example_id=filename, min_length=0, max_length=-1, allow_empty_notesequence=True)) 59 | 60 | # 분할된 버퍼를 시리얼라이즈 61 | to_process.append(examples[0].SerializeToString()) 62 | 63 | ############################################################# 64 | 65 | #시리얼라이즈한 버퍼를 iterator에 주입 66 | sess.run(iterator.initializer, {example:to_process}) 67 | 68 | # Inference 69 | predictions = list(estimator.predict(input_fn, yield_single_examples=False)) 70 | #가정 설정문으로 prediction size를 1로 보장 71 | assert len(predictions) == 1 72 | 73 | #예측 결과 불러오기 74 | frame_predictions = predictions[0]['frame_predictions'][0] 75 | onset_predictions = predictions[0]['onset_predictions'][0] # 치는 순간 76 | velocity_values = predictions[0]['velocity_values'][0] #강약 77 | 78 | #MIDI로 인코딩 79 | sequence_prediction = sequences_lib.pianoroll_to_note_sequence( 80 | frame_predictions, 81 | frames_per_second=data.hparams_frames_per_second(hparams), 82 | min_duration_ms=0, 83 | min_midi_pitch=constants.MIN_MIDI_PITCH, 84 | onset_predictions=onset_predictions, 85 | velocity_values=velocity_values) 86 | 87 | basename = os.path.split(os.path.splitext(filename)[0])[1] + '.mid' 88 | output_filename = os.path.join('', basename) 89 | 90 | midi_filename = (output_filename) 91 | midi_io.sequence_proto_to_midi_file(sequence_prediction, midi_filename) 92 | 93 | print('Program Ended, Your MIDI File is in', output_filename) 94 | 95 | sess.close() 96 | 97 | if __name__ == '__main__': 98 | file = input('Input Your .WAV Filename:') 99 | infer(file) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/python,pycharm 3 | # Edit at https://www.gitignore.io/?templates=python,pycharm 4 | 5 | ### PyCharm ### 6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 7 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 8 | 9 | # User-specific stuff 10 | .idea/**/workspace.xml 11 | .idea/**/tasks.xml 12 | .idea/**/usage.statistics.xml 13 | .idea/**/dictionaries 14 | .idea/**/shelf 15 | 16 | # Generated files 17 | .idea/**/contentModel.xml 18 | 19 | # Sensitive or high-churn files 20 | .idea/**/dataSources/ 21 | .idea/**/dataSources.ids 22 | .idea/**/dataSources.local.xml 23 | .idea/**/sqlDataSources.xml 24 | .idea/**/dynamic.xml 25 | .idea/**/uiDesigner.xml 26 | .idea/**/dbnavigator.xml 27 | 28 | # Gradle 29 | .idea/**/gradle.xml 30 | .idea/**/libraries 31 | 32 | # Gradle and Maven with auto-import 33 | # When using Gradle or Maven with auto-import, you should exclude module files, 34 | # since they will be recreated, and may cause churn. Uncomment if using 35 | # auto-import. 36 | # .idea/modules.xml 37 | # .idea/*.iml 38 | # .idea/modules 39 | # *.iml 40 | # *.ipr 41 | 42 | # CMake 43 | cmake-build-*/ 44 | 45 | # Mongo Explorer plugin 46 | .idea/**/mongoSettings.xml 47 | 48 | # File-based project format 49 | *.iws 50 | 51 | # IntelliJ 52 | out/ 53 | 54 | # mpeltonen/sbt-idea plugin 55 | .idea_modules/ 56 | 57 | # JIRA plugin 58 | atlassian-ide-plugin.xml 59 | 60 | # Cursive Clojure plugin 61 | .idea/replstate.xml 62 | 63 | # Crashlytics plugin (for Android Studio and IntelliJ) 64 | com_crashlytics_export_strings.xml 65 | crashlytics.properties 66 | crashlytics-build.properties 67 | fabric.properties 68 | 69 | # Editor-based Rest Client 70 | .idea/httpRequests 71 | 72 | # Android studio 3.1+ serialized cache file 73 | .idea/caches/build_file_checksums.ser 74 | 75 | ### PyCharm Patch ### 76 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 77 | 78 | # *.iml 79 | # modules.xml 80 | # .idea/misc.xml 81 | # *.ipr 82 | 83 | # Sonarlint plugin 84 | .idea/sonarlint 85 | 86 | ### Python ### 87 | # Byte-compiled / optimized / DLL files 88 | __pycache__/ 89 | *.py[cod] 90 | *$py.class 91 | 92 | # C extensions 93 | *.so 94 | 95 | # Distribution / packaging 96 | .Python 97 | build/ 98 | develop-eggs/ 99 | dist/ 100 | downloads/ 101 | eggs/ 102 | .eggs/ 103 | lib/ 104 | lib64/ 105 | parts/ 106 | sdist/ 107 | var/ 108 | wheels/ 109 | pip-wheel-metadata/ 110 | share/python-wheels/ 111 | *.egg-info/ 112 | .installed.cfg 113 | *.egg 114 | MANIFEST 115 | 116 | # PyInstaller 117 | # Usually these files are written by a python script from a template 118 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 119 | *.manifest 120 | *.spec 121 | 122 | # Installer logs 123 | pip-log.txt 124 | pip-delete-this-directory.txt 125 | 126 | # Unit test / coverage reports 127 | htmlcov/ 128 | .tox/ 129 | .nox/ 130 | .coverage 131 | .coverage.* 132 | .cache 133 | nosetests.xml 134 | coverage.xml 135 | *.cover 136 | .hypothesis/ 137 | .pytest_cache/ 138 | 139 | # Translations 140 | *.mo 141 | *.pot 142 | 143 | # Django stuff: 144 | *.log 145 | local_settings.py 146 | db.sqlite3 147 | db.sqlite3-journal 148 | 149 | # Flask stuff: 150 | instance/ 151 | .webassets-cache 152 | 153 | # Scrapy stuff: 154 | .scrapy 155 | 156 | # Sphinx documentation 157 | docs/_build/ 158 | 159 | # PyBuilder 160 | target/ 161 | 162 | # Jupyter Notebook 163 | .ipynb_checkpoints 164 | 165 | # IPython 166 | profile_default/ 167 | ipython_config.py 168 | 169 | # pyenv 170 | .python-version 171 | 172 | # pipenv 173 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 174 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 175 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 176 | # install all needed dependencies. 177 | #Pipfile.lock 178 | 179 | # celery beat schedule file 180 | celerybeat-schedule 181 | 182 | # SageMath parsed files 183 | *.sage.py 184 | 185 | # Environments 186 | .env 187 | .venv 188 | env/ 189 | venv/ 190 | ENV/ 191 | env.bak/ 192 | venv.bak/ 193 | 194 | # Spyder project settings 195 | .spyderproject 196 | .spyproject 197 | 198 | # Rope project settings 199 | .ropeproject 200 | 201 | # mkdocs documentation 202 | /site 203 | 204 | # mypy 205 | .mypy_cache/ 206 | .dmypy.json 207 | dmypy.json 208 | 209 | # Pyre type checker 210 | .pyre/ 211 | 212 | sample/ 213 | train/* 214 | !train/TRAINED_MODEL_HERE.md 215 | 216 | # End of https://www.gitignore.io/api/python,pycharm -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 giopaik. All rights reserved. 2 | 3 | Magenta and TensorFlow is made by Google, under Apache License 2.0 4 | 5 | Apache License 6 | Version 2.0, January 2004 7 | http://www.apache.org/licenses/ 8 | 9 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 10 | 11 | 1. Definitions. 12 | 13 | "License" shall mean the terms and conditions for use, reproduction, 14 | and distribution as defined by Sections 1 through 9 of this document. 15 | 16 | "Licensor" shall mean the copyright owner or entity authorized by 17 | the copyright owner that is granting the License. 18 | 19 | "Legal Entity" shall mean the union of the acting entity and all 20 | other entities that control, are controlled by, or are under common 21 | control with that entity. For the purposes of this definition, 22 | "control" means (i) the power, direct or indirect, to cause the 23 | direction or management of such entity, whether by contract or 24 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 25 | outstanding shares, or (iii) beneficial ownership of such entity. 26 | 27 | "You" (or "Your") shall mean an individual or Legal Entity 28 | exercising permissions granted by this License. 29 | 30 | "Source" form shall mean the preferred form for making modifications, 31 | including but not limited to software source code, documentation 32 | source, and configuration files. 33 | 34 | "Object" form shall mean any form resulting from mechanical 35 | transformation or translation of a Source form, including but 36 | not limited to compiled object code, generated documentation, 37 | and conversions to other media types. 38 | 39 | "Work" shall mean the work of authorship, whether in Source or 40 | Object form, made available under the License, as indicated by a 41 | copyright notice that is included in or attached to the work 42 | (an example is provided in the Appendix below). 43 | 44 | "Derivative Works" shall mean any work, whether in Source or Object 45 | form, that is based on (or derived from) the Work and for which the 46 | editorial revisions, annotations, elaborations, or other modifications 47 | represent, as a whole, an original work of authorship. For the purposes 48 | of this License, Derivative Works shall not include works that remain 49 | separable from, or merely link (or bind by name) to the interfaces of, 50 | the Work and Derivative Works thereof. 51 | 52 | "Contribution" shall mean any work of authorship, including 53 | the original version of the Work and any modifications or additions 54 | to that Work or Derivative Works thereof, that is intentionally 55 | submitted to Licensor for inclusion in the Work by the copyright owner 56 | or by an individual or Legal Entity authorized to submit on behalf of 57 | the copyright owner. For the purposes of this definition, "submitted" 58 | means any form of electronic, verbal, or written communication sent 59 | to the Licensor or its representatives, including but not limited to 60 | communication on electronic mailing lists, source code control systems, 61 | and issue tracking systems that are managed by, or on behalf of, the 62 | Licensor for the purpose of discussing and improving the Work, but 63 | excluding communication that is conspicuously marked or otherwise 64 | designated in writing by the copyright owner as "Not a Contribution." 65 | 66 | "Contributor" shall mean Licensor and any individual or Legal Entity 67 | on behalf of whom a Contribution has been received by Licensor and 68 | subsequently incorporated within the Work. 69 | 70 | 2. Grant of Copyright License. Subject to the terms and conditions of 71 | this License, each Contributor hereby grants to You a perpetual, 72 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 73 | copyright license to reproduce, prepare Derivative Works of, 74 | publicly display, publicly perform, sublicense, and distribute the 75 | Work and such Derivative Works in Source or Object form. 76 | 77 | 3. Grant of Patent License. Subject to the terms and conditions of 78 | this License, each Contributor hereby grants to You a perpetual, 79 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 80 | (except as stated in this section) patent license to make, have made, 81 | use, offer to sell, sell, import, and otherwise transfer the Work, 82 | where such license applies only to those patent claims licensable 83 | by such Contributor that are necessarily infringed by their 84 | Contribution(s) alone or by combination of their Contribution(s) 85 | with the Work to which such Contribution(s) was submitted. If You 86 | institute patent litigation against any entity (including a 87 | cross-claim or counterclaim in a lawsuit) alleging that the Work 88 | or a Contribution incorporated within the Work constitutes direct 89 | or contributory patent infringement, then any patent licenses 90 | granted to You under this License for that Work shall terminate 91 | as of the date such litigation is filed. 92 | 93 | 4. Redistribution. You may reproduce and distribute copies of the 94 | Work or Derivative Works thereof in any medium, with or without 95 | modifications, and in Source or Object form, provided that You 96 | meet the following conditions: 97 | 98 | (a) You must give any other recipients of the Work or 99 | Derivative Works a copy of this License; and 100 | 101 | (b) You must cause any modified files to carry prominent notices 102 | stating that You changed the files; and 103 | 104 | (c) You must retain, in the Source form of any Derivative Works 105 | that You distribute, all copyright, patent, trademark, and 106 | attribution notices from the Source form of the Work, 107 | excluding those notices that do not pertain to any part of 108 | the Derivative Works; and 109 | 110 | (d) If the Work includes a "NOTICE" text file as part of its 111 | distribution, then any Derivative Works that You distribute must 112 | include a readable copy of the attribution notices contained 113 | within such NOTICE file, excluding those notices that do not 114 | pertain to any part of the Derivative Works, in at least one 115 | of the following places: within a NOTICE text file distributed 116 | as part of the Derivative Works; within the Source form or 117 | documentation, if provided along with the Derivative Works; or, 118 | within a display generated by the Derivative Works, if and 119 | wherever such third-party notices normally appear. The contents 120 | of the NOTICE file are for informational purposes only and 121 | do not modify the License. You may add Your own attribution 122 | notices within Derivative Works that You distribute, alongside 123 | or as an addendum to the NOTICE text from the Work, provided 124 | that such additional attribution notices cannot be construed 125 | as modifying the License. 126 | 127 | You may add Your own copyright statement to Your modifications and 128 | may provide additional or different license terms and conditions 129 | for use, reproduction, or distribution of Your modifications, or 130 | for any such Derivative Works as a whole, provided Your use, 131 | reproduction, and distribution of the Work otherwise complies with 132 | the conditions stated in this License. 133 | 134 | 5. Submission of Contributions. Unless You explicitly state otherwise, 135 | any Contribution intentionally submitted for inclusion in the Work 136 | by You to the Licensor shall be under the terms and conditions of 137 | this License, without any additional terms or conditions. 138 | Notwithstanding the above, nothing herein shall supersede or modify 139 | the terms of any separate license agreement you may have executed 140 | with Licensor regarding such Contributions. 141 | 142 | 6. Trademarks. This License does not grant permission to use the trade 143 | names, trademarks, service marks, or product names of the Licensor, 144 | except as required for reasonable and customary use in describing the 145 | origin of the Work and reproducing the content of the NOTICE file. 146 | 147 | 7. Disclaimer of Warranty. Unless required by applicable law or 148 | agreed to in writing, Licensor provides the Work (and each 149 | Contributor provides its Contributions) on an "AS IS" BASIS, 150 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 151 | implied, including, without limitation, any warranties or conditions 152 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 153 | PARTICULAR PURPOSE. You are solely responsible for determining the 154 | appropriateness of using or redistributing the Work and assume any 155 | risks associated with Your exercise of permissions under this License. 156 | 157 | 8. Limitation of Liability. In no event and under no legal theory, 158 | whether in tort (including negligence), contract, or otherwise, 159 | unless required by applicable law (such as deliberate and grossly 160 | negligent acts) or agreed to in writing, shall any Contributor be 161 | liable to You for damages, including any direct, indirect, special, 162 | incidental, or consequential damages of any character arising as a 163 | result of this License or out of the use or inability to use the 164 | Work (including but not limited to damages for loss of goodwill, 165 | work stoppage, computer failure or malfunction, or any and all 166 | other commercial damages or losses), even if such Contributor 167 | has been advised of the possibility of such damages. 168 | 169 | 9. Accepting Warranty or Additional Liability. While redistributing 170 | the Work or Derivative Works thereof, You may choose to offer, 171 | and charge a fee for, acceptance of support, warranty, indemnity, 172 | or other liability obligations and/or rights consistent with this 173 | License. However, in accepting such obligations, You may act only 174 | on Your own behalf and on Your sole responsibility, not on behalf 175 | of any other Contributor, and only if You agree to indemnify, 176 | defend, and hold each Contributor harmless for any liability 177 | incurred by, or claims asserted against, such Contributor by reason 178 | of your accepting any such warranty or additional liability. 179 | 180 | END OF TERMS AND CONDITIONS 181 | 182 | APPENDIX: How to apply the Apache License to your work. 183 | 184 | To apply the Apache License to your work, attach the following 185 | boilerplate notice, with the fields enclosed by brackets "[]" 186 | replaced with your own identifying information. (Don't include 187 | the brackets!) The text should be enclosed in the appropriate 188 | comment syntax for the file format. We also recommend that a 189 | file or class name and description of purpose be included on the 190 | same "printed page" as the copyright notice for easier 191 | identification within third-party archives. 192 | 193 | Copyright 2015, The TensorFlow Authors. 194 | 195 | Licensed under the Apache License, Version 2.0 (the "License"); 196 | you may not use this file except in compliance with the License. 197 | You may obtain a copy of the License at 198 | 199 | http://www.apache.org/licenses/LICENSE-2.0 200 | 201 | Unless required by applicable law or agreed to in writing, software 202 | distributed under the License is distributed on an "AS IS" BASIS, 203 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 204 | See the License for the specific language governing permissions and 205 | limitations under the License. --------------------------------------------------------------------------------