├── flamegraph.png ├── .travis.yml ├── .gitignore ├── .github └── dependabot.yml ├── Cargo.toml ├── tests ├── double.rs ├── flamed_const.rs ├── flamed.rs └── opt_name.rs ├── README.md ├── src └── lib.rs └── LICENSE /flamegraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llogiq/flamer/HEAD/flamegraph.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: nightly 3 | sudo: false 4 | cache: cargo 5 | script: 6 | - cargo test 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled files 2 | *.o 3 | *.so 4 | *.rlib 5 | *.dll 6 | 7 | # Executables 8 | *.exe 9 | 10 | # Generated by Cargo 11 | /target/ 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "04:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "flamer" 3 | version = "0.5.0" 4 | authors = ["Andre Bogus "] 5 | description = "a procedural macro to insert `flame::start_guard(_)` calls" 6 | license = "Apache-2.0" 7 | repository = "https://github.com/llogiq/flamer" 8 | readme = "README.md" 9 | keywords = ["flame-graph", "profiling", "compiler-plugin"] 10 | exclude = [".travis.yml", "flamegraph.png"] 11 | 12 | [lib] 13 | proc_macro = true 14 | 15 | [dependencies] 16 | flame = "0.2.2" 17 | syn = { version = "2.0", features = ["extra-traits", "full", "fold", "parsing"] } 18 | quote = "1.0" 19 | 20 | [features] 21 | # WARNING: This Cargo feature is not intended for public usage! 22 | # Used to test `flamer` for module support which currently requires nightly 23 | # Rust. 24 | test-nightly = [] 25 | -------------------------------------------------------------------------------- /tests/double.rs: -------------------------------------------------------------------------------- 1 | //! Test double attrs. 2 | 3 | #![cfg(feature = "test-nightly")] 4 | #![feature(proc_macro_hygiene)] 5 | 6 | extern crate flame; 7 | #[macro_use] extern crate flamer; 8 | 9 | #[flame] 10 | mod inner { 11 | fn a() { 12 | // nothing to do here 13 | } 14 | 15 | #[flame] 16 | fn b() { 17 | a() 18 | } 19 | 20 | #[noflame] 21 | pub fn c() { 22 | b() 23 | } 24 | } 25 | 26 | #[test] 27 | fn main() { 28 | inner::c(); 29 | let spans = flame::spans(); 30 | assert_eq!(1, spans.len()); 31 | let roots = &spans[0]; 32 | println!("{:?}",roots); 33 | // if more than 2 roots, a() was flamed twice or c was flamed 34 | // main is missing because main isn't closed here 35 | assert_eq!("b", roots.name); 36 | assert_eq!(1, roots.children.len()); 37 | assert_eq!("inner::a", roots.children[0].name); 38 | } 39 | -------------------------------------------------------------------------------- /tests/flamed_const.rs: -------------------------------------------------------------------------------- 1 | //! Test `flamer` usage with const functions and methods. 2 | 3 | #![cfg(feature = "test-nightly")] 4 | #![feature(proc_macro_hygiene)] 5 | 6 | extern crate flame; 7 | extern crate flamer; 8 | 9 | use flamer::flame; 10 | 11 | #[flame] 12 | mod inner { 13 | const fn e() -> u32 { 14 | 2 15 | } 16 | 17 | fn d() -> u32 { 18 | e() << e() 19 | } 20 | 21 | fn c() -> u32 { 22 | d() * d() * d() - 1 23 | } 24 | 25 | fn b() -> u32 { 26 | (0..3).map(|_| c()).fold(0, |x, y| x + y) 27 | } 28 | 29 | pub fn a() -> u32 { 30 | let mut result = 0; 31 | for _ in 0..3 { 32 | result += b() 33 | } 34 | result / 10 35 | } 36 | } 37 | 38 | #[test] 39 | fn test_flame() { 40 | assert_eq!(459, inner::a()); 41 | let spans = flame::spans(); 42 | assert_eq!(1, spans.len()); 43 | let roots = &spans[0]; 44 | assert_eq!(3, roots.children.len()); 45 | } 46 | -------------------------------------------------------------------------------- /tests/flamed.rs: -------------------------------------------------------------------------------- 1 | //! Test basic `flamer` usage. 2 | 3 | #![cfg(feature = "test-nightly")] 4 | #![feature(proc_macro_hygiene)] 5 | 6 | extern crate flame; 7 | #[macro_use] extern crate flamer; 8 | 9 | #[flame] 10 | mod inner { 11 | fn e() -> u32 { 12 | 2 13 | } 14 | 15 | fn d() -> u32 { 16 | e() << e() 17 | } 18 | 19 | fn c() -> u32 { 20 | d() * d() * d() - 1 21 | } 22 | 23 | fn b() -> u32 { 24 | (0..3).map(|_| c()).fold(0, |x, y| x + y) 25 | } 26 | 27 | pub fn a() -> u32 { 28 | let mut result = 0; 29 | for _ in 0..3 { 30 | result += b() 31 | } 32 | result / 10 33 | } 34 | 35 | #[noflame] 36 | #[allow(unused)] 37 | mod flamed { 38 | pub fn id() { 39 | } 40 | } 41 | } 42 | 43 | use inner::*; 44 | 45 | #[test] 46 | fn test_flame() { 47 | assert_eq!(459, a()); 48 | let spans = flame::spans(); 49 | assert_eq!(1, spans.len()); 50 | let roots = &spans[0]; 51 | assert_eq!(3, roots.children.len()); 52 | } 53 | -------------------------------------------------------------------------------- /tests/opt_name.rs: -------------------------------------------------------------------------------- 1 | //! Test optional prefix. 2 | 3 | extern crate flame; 4 | extern crate flamer; 5 | 6 | use flamer::{flame, noflame}; 7 | 8 | #[flame("top")] 9 | fn a() { 10 | let l = Lower {}; 11 | l.a(); 12 | } 13 | 14 | #[flame] 15 | fn b() { 16 | a() 17 | } 18 | 19 | #[noflame] 20 | fn c() { 21 | b() 22 | } 23 | 24 | pub struct Lower; 25 | 26 | impl Lower { 27 | #[flame("lower")] 28 | pub fn a(self) { 29 | // nothing to do here 30 | } 31 | } 32 | 33 | #[test] 34 | fn main() { 35 | c(); 36 | let spans = flame::spans(); 37 | assert_eq!(1, spans.len()); 38 | let roots = &spans[0]; 39 | println!("{:?}",roots); 40 | // if more than 2 roots, a() was flamed twice or c was flamed 41 | // main is missing because main isn't closed here 42 | assert_eq!("b", roots.name); 43 | assert_eq!(1, roots.children.len()); 44 | assert_eq!("top::a", roots.children[0].name); 45 | assert_eq!(1, roots.children[0].children.len()); 46 | assert_eq!("lower::a", roots.children[0].children[0].name); 47 | } 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A proc macro to insert appropriate `flame::start_guard(_)` calls (for use with 2 | [flame](https://github.com/TyOverby/flame)) 3 | 4 | [![Build Status](https://travis-ci.org/llogiq/flamer.svg)](https://travis-ci.org/llogiq/flamer) 5 | [![Current Version](https://img.shields.io/crates/v/flamer.svg)](https://crates.io/crates/flamer) 6 | [![Docs](https://docs.rs/flamer/badge.svg)](https://docs.rs/flamer) 7 | ![Supported Rust Versions](https://img.shields.io/badge/rustc-1.30+-yellow.svg) 8 | 9 | **This proc macro requires Rust 1.30.** 10 | Because flamer is a proc macro attribute, it uses APIs stabilized in Rust 1.30. 11 | 12 | ## Usage: 13 | 14 | In your Cargo.toml add `flame` and `flamer` to your dependencies: 15 | 16 | ```toml 17 | [dependencies] 18 | flame = "0.2.2" 19 | flamer = "0.5" 20 | ``` 21 | 22 | Then in your crate root, add the following: 23 | 24 | ```rust 25 | extern crate flame; 26 | #[macro_use] extern crate flamer; 27 | 28 | #[flame] 29 | // The item to apply `flame` to goes here. 30 | ``` 31 | 32 | Unfortunately, currently stable Rust doesn't allow custom attributes on modules. 33 | To use `#[flame]` on modules you need a nightly Rust with 34 | `#![feature(proc_macro_hygiene)]` in the crate root 35 | ([related issue](https://github.com/rust-lang/rust/issues/54727)): 36 | 37 | ```rust 38 | #![feature(proc_macro_hygiene)] 39 | 40 | extern crate flame; 41 | #[macro_use] extern crate flamer; 42 | 43 | #[flame] 44 | mod flamed_module { .. } 45 | ``` 46 | 47 | You may also opt for an *optional dependency*. In that case your Cargo.toml should have: 48 | 49 | ```toml 50 | [dependencies] 51 | flame = { version = "0.2.2", optional = true } 52 | flamer = { version = "0.3", optional = true } 53 | 54 | [features] 55 | default = [] 56 | flame_it = ["flame", "flamer"] 57 | ``` 58 | 59 | And your crate root should contain: 60 | 61 | ```rust 62 | #[cfg(feature = "flame_it")] 63 | extern crate flame; 64 | #[cfg(feature = "flame_it")] 65 | #[macro_use] extern crate flamer; 66 | 67 | // as well as the following instead of `#[flame]` 68 | #[cfg_attr(feature = "flame_it", flame)] 69 | // The item to apply `flame` to goes here. 70 | ``` 71 | 72 | For nightly module support, also add 73 | `#![cfg_attr(feature = "flame_it", feature(proc_macro_hygiene))]` in the crate 74 | root: 75 | 76 | ```rust 77 | #![cfg_attr(feature = "flame_it", feature(proc_macro_hygiene))] 78 | 79 | #[cfg(feature = "flame_it")] 80 | extern crate flame; 81 | #[cfg(feature = "flame_it")] 82 | #[macro_use] extern crate flamer; 83 | 84 | // as well as the following instead of `#[flame]` 85 | #[cfg_attr(feature = "flame_it", flame)] 86 | mod flamed_module { .. } 87 | ``` 88 | 89 | You should then be able to annotate every item (alas, currently not the whole 90 | crate; see the 91 | [custom inner attribute](https://github.com/rust-lang/rust/issues/54726) issue 92 | for more details) with `#[flame]` annotations. 93 | You can also use `#[noflame]` annotations to disable instrumentations for 94 | subitems of `#[flame]`d items. Note that this only instruments the annotated 95 | methods, it does not print out the results. 96 | 97 | The `flame` annotation can also take an optional parameter specifying a string 98 | to prefix to enclosed method names. 99 | This is especially useful when annotating multiple methods with the same name, 100 | but in different modules. 101 | 102 | ```rust 103 | #[flame("prefix")] 104 | fn method_name() { 105 | //The corresponding block on the flamegraph will be named "prefix::method_name" 106 | } 107 | ``` 108 | 109 | ## Full Example 110 | ```rust 111 | use std::fs::File; 112 | 113 | use flame as f; 114 | use flamer::flame; 115 | 116 | #[flame] 117 | fn make_vec(size: usize) -> Vec { 118 | // using the original lib is still possible 119 | let mut res = f::span_of("vec init", || vec![0_u32; size]); 120 | for x in 0..size { 121 | res[x] = ((x + 10)/3) as u32; 122 | } 123 | let mut waste_time = 0; 124 | for i in 0..size*10 { 125 | waste_time += i 126 | } 127 | res 128 | } 129 | #[flame] 130 | fn more_computing(i: usize) { 131 | for x in 0..(i * 100) { 132 | let mut v = make_vec(x); 133 | let x = Vec::from(&v[..]); 134 | for i in 0..v.len() { 135 | let flip = (v.len() - 1) - i as usize; 136 | v[i] = x[flip]; 137 | } 138 | } 139 | } 140 | #[flame] 141 | fn some_computation() { 142 | for i in 0..15 { 143 | more_computing(i); 144 | } 145 | } 146 | 147 | #[flame] 148 | fn main() { 149 | some_computation(); 150 | // in order to create the flamegraph you must call one of the 151 | // flame::dump_* functions. 152 | f::dump_html(File::create("flamegraph.html").unwrap()).unwrap(); 153 | } 154 | ``` 155 | ![flamegraph](./flamegraph.png "Flamegraph example") 156 | 157 | Refer to [flame's documentation](https://docs.rs/flame) to see how output works. 158 | 159 | License: Apache 2.0 160 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A procedural attribute-macro to insert `flame` calls into code 2 | //! 3 | //! The feature parity varies between versions of Rust: 4 | //! * On stable and beta, you can annotate functions with `#[flame]`. 5 | //! * On nightly, you can also annotate modules with `#[flame]`. 6 | //! You will need to add `#![feature(proc_macro_hygiene)]` in the crate root 7 | //! ([related issue][proc_macro_hygiene tracking issue]). 8 | //! 9 | //! Alas, currently you cannot annotate the whole crate. For details about why, 10 | //! see the [custom inner attributes] issue. 11 | //! 12 | //! You can also annotate modules, functions or other items with `#[noflame]` to 13 | //! omit them from the flame tracing. 14 | //! For any given Rust version, the list of supported items for `#[noflame]` is 15 | //! the same as for `#[flame]`. 16 | //! 17 | //! [proc_macro_hygiene tracking issue]: https://github.com/rust-lang/rust/issues/54727 18 | //! [custom inner attributes]: https://github.com/rust-lang/rust/issues/54726 19 | 20 | extern crate proc_macro; 21 | extern crate quote; 22 | extern crate syn; 23 | 24 | use self::proc_macro::TokenStream; 25 | use quote::quote; 26 | use syn::fold::{self, Fold}; 27 | use syn::parse::{Parse, ParseStream, Result}; 28 | use syn::punctuated::Punctuated; 29 | 30 | use syn::{ 31 | parse_macro_input, parse_quote, Attribute, ImplItemFn, Item, ItemFn, ItemImpl, ItemMod, 32 | ItemTrait, Token, TraitItemFn, 33 | }; 34 | 35 | #[derive(Default)] 36 | struct Flamer { 37 | id_stack: Vec, 38 | } 39 | 40 | impl Flamer { 41 | fn push(&mut self, ident: String) { 42 | self.id_stack.push(ident); 43 | } 44 | 45 | fn pop(&mut self) { 46 | let _ = self.id_stack.pop(); 47 | } 48 | 49 | fn name(&self) -> String { 50 | self.id_stack.join("::") 51 | } 52 | 53 | fn is_noflame(&self, i: &[Attribute]) -> bool { 54 | i.iter().any(|ref a| { 55 | if a.path().segments.len() == 1 { 56 | let ident = &a.path().segments.iter().next().unwrap().ident; 57 | ident == "flame" || ident == "noflame" 58 | } else { 59 | false 60 | } 61 | }) 62 | } 63 | } 64 | 65 | impl Parse for Flamer { 66 | fn parse(input: ParseStream) -> Result { 67 | let vars = Punctuated::::parse_terminated(input)?; 68 | Ok(Flamer { 69 | id_stack: vars.into_iter().map(|s| s.value()).collect::>(), 70 | }) 71 | } 72 | } 73 | 74 | impl Fold for Flamer { 75 | fn fold_item_mod(&mut self, i: ItemMod) -> ItemMod { 76 | if self.is_noflame(&i.attrs) { 77 | return i; 78 | } 79 | self.push(i.ident.to_string()); 80 | let item_mod = fold::fold_item_mod(self, i); 81 | self.pop(); 82 | item_mod 83 | } 84 | 85 | fn fold_item_trait(&mut self, i: ItemTrait) -> ItemTrait { 86 | if self.is_noflame(&i.attrs) { 87 | return i; 88 | } 89 | self.push(i.ident.to_string()); 90 | let t = fold::fold_item_trait(self, i); 91 | self.pop(); 92 | t 93 | } 94 | 95 | fn fold_trait_item_fn(&mut self, i: TraitItemFn) -> TraitItemFn { 96 | if i.sig.constness.is_some() || self.is_noflame(&i.attrs) { 97 | return i; 98 | } 99 | self.push(i.sig.ident.to_string()); 100 | let m = fold::fold_trait_item_fn(self, i); 101 | self.pop(); 102 | m 103 | } 104 | 105 | fn fold_item_impl(&mut self, i: ItemImpl) -> ItemImpl { 106 | if self.is_noflame(&i.attrs) { 107 | return i; 108 | } 109 | if let Some((_, ref path, _)) = i.trait_ { 110 | self.push(format!("{:?} as {:?}", &i.self_ty, path)); 111 | } else { 112 | self.push(format!("{:?}", &i.self_ty)); 113 | } 114 | let ii = fold::fold_item_impl(self, i); 115 | self.pop(); 116 | ii 117 | } 118 | 119 | fn fold_impl_item_fn(&mut self, i: ImplItemFn) -> ImplItemFn { 120 | if i.sig.constness.is_some() || self.is_noflame(&i.attrs) { 121 | return i; 122 | } 123 | self.push(i.sig.ident.to_string()); 124 | let method = fold::fold_impl_item_fn(self, i); 125 | self.pop(); 126 | method 127 | } 128 | 129 | fn fold_item_fn(&mut self, i: ItemFn) -> ItemFn { 130 | if self.is_noflame(&i.attrs) { 131 | return i; 132 | } 133 | if i.sig.constness.is_some() { 134 | return fold::fold_item_fn(self, i); 135 | } 136 | let mut i = i; 137 | self.push(i.sig.ident.to_string()); 138 | let name = self.name(); 139 | let stmts = ::std::mem::replace( 140 | &mut i.block.stmts, 141 | vec![parse_quote! { 142 | let _flame_guard = ::flame::start_guard(#name); 143 | }], 144 | ); 145 | for stmt in stmts { 146 | i.block.stmts.push(fold::fold_stmt(self, stmt)); 147 | } 148 | self.pop(); 149 | i 150 | } 151 | } 152 | 153 | #[proc_macro_attribute] 154 | pub fn flame(attrs: TokenStream, code: TokenStream) -> TokenStream { 155 | let input = parse_macro_input!(code as Item); 156 | let mut flamer = parse_macro_input!(attrs as Flamer); 157 | let item = fold::fold_item(&mut flamer, input); 158 | TokenStream::from(quote!(#item)) 159 | } 160 | 161 | #[proc_macro_attribute] 162 | pub fn noflame(_attrs: TokenStream, code: TokenStream) -> TokenStream { 163 | code 164 | } 165 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------