├── .gitignore ├── c ├── Makefile ├── README.md └── tinysh.c ├── Cargo.lock ├── Cargo.toml ├── orig ├── tbr.c ├── README.md └── tbr.hint.txt ├── README.md ├── src └── main.rs └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /c/Makefile: -------------------------------------------------------------------------------- 1 | tinysh: tinysh.o 2 | $(CC) $^ -Wall -Wextra -pedantic -std=c89 -o $@ 3 | 4 | clean: 5 | rm -f tinysh.o tinysh 6 | 7 | .PHONY: clean 8 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "tinysh" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tinysh" 3 | version = "0.1.0" 4 | authors = ["Serge Zaitsev "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /c/README.md: -------------------------------------------------------------------------------- 1 | # C89 implmenetation 2 | 3 | This is a deobfuscated version of the tinysh from the `../orig` folder. It 4 | should work with any modern C compiler and is supposedly easier to read. 5 | 6 | It has the same bugs and limitations (if not more?) as the original implementation. 7 | -------------------------------------------------------------------------------- /orig/tbr.c: -------------------------------------------------------------------------------- 1 | 2 | #define D ,close( 3 | 4 | char *c,q [512 ],m[ 256 5 | ],*v[ 99], **u, *i[3];int f[2],p;main (){for 6 | (m[m [60]= m[62 ]=32 ]=m[* m=124 [m]= 9]=6; 7 | e(-8) ,gets (1+( c=q) )|| exit (0); r(0,0) 8 | )for( ;*++ c;); }r(t, o){ *i=i [2]= 0;for 9 | (u=v +98 ;m[*--c] ^9;m [*c] &32 ?i[*c 10 | &2]= *u,u- v^98 &&++u: 11 | 12 | 3 )if(!m[*c]){for(*++c=0;!m[*--c];); 13 | * --u= ++c;}u-v^98?strcmp(*u,"cd")?*c?pipe(f),o=f[ 14 | 1 ]: 15 | 4 ,(p=fork())?e(p),o?r(o,0)D o)D*f): 16 | 1 ,wait(0):(o?dup2(*f,0)D*f)D o):*i? 17 | 5 D 0),e(open(*i,0)): 18 | 9 ,t?dup2(t,1)D t):i[ 19 | 2 ]? 20 | 6 D 1),e(creat(i[2],438)): 21 | 5 ,e(execvp(*u,u))):e(chdir(u[1])*2): 22 | 3 ;}e(x){x<0?write(2,"?\n$ "-x/4,2),x+1||exit(1): 23 | 5 ;} 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tinysh 2 | 3 | > If you hold a UNIX shell to your ear, you can hear the C. 4 | 5 | This is a tiny UNIX shell, implemented in Rust and in C. 6 | It is derived from the brilliant IOCCC submission back in 1990 by Sean Dorward. The repository includes the original IOCCC version, as well as the modernized deobfuscated version in C89, and a complete rewrite in Rust. 7 | 8 | To run the shell do: `cargo run`. Or, better, `rlwrap cargo run` if you want to have a history of commands. 9 | 10 | To run the C version do: `cd c && make && ./tinysh`. 11 | 12 | The shell supports: 13 | 14 | * Simple commands, i.e. `vim`, `echo hello world` etc. 15 | * Pipelines, i.e. `ls | Cargo | wc -l'. 16 | * File redirection, i.e. `echo hello > x` and `cat < x | grep hello`. 17 | 18 | Pretty good for ~100 lines of code in either C or Rust. However, it does not support: 19 | 20 | * `>>` append operator. 21 | * `2>` or `2>&1` or anything more complex. 22 | * `&`, although that should be trivial to add. 23 | * Globs, variables, conditionals, loops, functions and it will never be a proper POSIX shell. 24 | 25 | Only a toy. Use and explore at your own risk. However, PRs are welcome for bugfixes, or if the additional functionality would not increase the complexity. 26 | -------------------------------------------------------------------------------- /orig/README.md: -------------------------------------------------------------------------------- 1 | # Original implementation 2 | 3 | This is the original implementation of a tiny UNIX shell, submitted by Sean Dorward to The International Obfuscated C Code Contest (http://ioccc.org/) in 1990. The submission actually won the "Best Utility" nomation. 4 | 5 | If you try to comile it - you are likely to get "void value not ignored as it ought to be" error from the compiler. 6 | To fix it - add a custom `int _exit(int)` function that would do the exit() and return some int value. The original app was written in K&R style, which violates modern standard expectations. 7 | 8 | The notes from the author decoded are: 9 | 10 | ``` 11 | This program is a rudimentary shell. It does i/o redirection, pipes 12 | and cd. It flags errors on failed chdir's, open's, creat's 13 | execvp's, fork's and a few syntax errors. 14 | 15 | This program is obfuscated in a few notable ways: apart from the 16 | layout (an unformatted (but crunched) version is included for 17 | people who want to put this through cb) it makes clever use of a 18 | write statement, so that the same statement can be used to print 19 | errors and the prompt. By calling the error function with the value 20 | -8, the pointer offset in the expression "?\n$ "-x/4 goes from 0 to 21 | 2. Presto! A prompt. For errors with numbers smaller than -4 22 | (i.e., UNIX system calls) a question mark is printed. 23 | 24 | The error value of chdir is doubled so that we don't exit from the 25 | parent shell on a chdir error (since e() exits on -1 errors only). 26 | All other system call failures exit since they are from subshells. 27 | 28 | Recursion is sneakily employed to avoid a second call to fork(), 29 | and the line is parsed in a fairly bizarre fashion: backwards. The 30 | heart of the program, that is, the part which performs all forks, 31 | execs, opens, etc. is ONE C STATEMENT. 32 | 33 | The meta-values array is initialized in a bizarre fashion, and the 34 | subsequent checks for the '<' and '>' are performed in a single 35 | statement using a mask, since you know that '>'&2 is 0, whereas 36 | '<'&2 is 2. Other such micro-obfuscations abound. 37 | 38 | Finally, it is notable that the code was hacked for minimality. If 39 | you look at the compressed version, you will be hard-pressed to 40 | eliminate more than a few characters (we can't see how to make it 41 | any smaller!). 550 characters is pretty lean for a shell that does 42 | this much. 43 | 44 | BUGS 45 | 46 | The syntax of the shell has not been fully explored, but if you try 47 | to redirect in the same direction more than once, only one 48 | redirection is performed. This is a "feature" of the way the line 49 | is parsed; a pointer to the stack of arguments is assigned and an 50 | argument is stolen every time a ">" or "<" is encountered. The 51 | shell flags an error if no arguments are on the stack. Thus, for 52 | example: 53 | cat > foo > bar 54 | cats to foo, since it was pushed last, but 55 | cat > > foo bar 56 | cats to bar, since bar was pushed under foo. (remember we're 57 | parsing right-left) 58 | 59 | Depending on your flavor of UNIX, cd without an argument will 60 | either produce an error or just do nothing. 61 | 62 | There is just one error message, the question mark, but hey, that's 63 | all ed does too. 64 | ``` 65 | -------------------------------------------------------------------------------- /c/tinysh.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* Display prompt */ 10 | static void prompt() { write(2, "$ ", 2); } 11 | 12 | /* Display error message, optionally - exit */ 13 | static void err(int retval, int fatal) { 14 | if (retval < 0) { 15 | write(2, "?\n", 2); 16 | if (fatal) { 17 | exit(1); 18 | } 19 | } 20 | } 21 | 22 | /* Helper functions to detect token class */ 23 | static int is_delim(int c) { return c == 0 || c == '|'; } 24 | static int is_redir(int c) { return c == '>' || c == '<'; } 25 | static int is_blank(int c) { return c == ' ' || c == '\t' || c == '\n'; } 26 | static int is_special(int c) { 27 | return is_delim(c) || is_redir(c) || is_blank(c); 28 | } 29 | 30 | /* Recursively run right-most part of the command line printing output to the 31 | * `t` file descriptor */ 32 | static void run(char *c, int t) { 33 | char *redir_stdin = NULL; 34 | char *redir_stdout = NULL; 35 | int pipefds[2] = {0, 0}; 36 | int outfd = 0; 37 | char *v[99] = {0}; 38 | char **u; 39 | u = &v[98]; /* end of words */ 40 | for (;;) { 41 | c--; 42 | if (is_delim(*c)) { /* if NIL (start of string) or pipe: break */ 43 | break; 44 | } 45 | if (!is_special(*c)) { 46 | /* Copy word of regular chars into previous u */ 47 | c++; 48 | *c = 0; /* null-terminate */ 49 | for (; !is_special(*--c);) { 50 | } 51 | *--u = ++c; 52 | } 53 | /* If < or > */ 54 | if (is_redir(*c)) { 55 | if (*c == '<') { 56 | redir_stdin = *u; 57 | } else { 58 | redir_stdout = *u; 59 | } 60 | if (u - v != 98) { 61 | u++; 62 | } 63 | } 64 | } 65 | 66 | if (u - v == 98) { /* empty input */ 67 | return; 68 | } 69 | if (strcmp(*u, "cd") == 0) { 70 | err(chdir(u[1]), 0); 71 | return; /* actually, should run() again */ 72 | } 73 | if (*c) { 74 | pipe(pipefds); 75 | outfd = pipefds[1]; /* write end of the pipe */ 76 | } 77 | int pid = fork(); 78 | if (pid) { 79 | /* Parent or error */ 80 | err(pid, 1); 81 | if (outfd) { 82 | run(c, outfd); /* parse the rest of the cmdline */ 83 | close(outfd); /* close output fd */ 84 | close(pipefds[0]); /* close read end of the pipe */ 85 | } 86 | wait(0); 87 | return; 88 | } 89 | if (outfd) { 90 | dup2(pipefds[0], 0); /* dup read fd to stdin */ 91 | close(pipefds[0]); /* close read fd */ 92 | close(outfd); /* close output */ 93 | } 94 | 95 | if (redir_stdin) { 96 | close(0); /* replace stdin with redir_stdin */ 97 | err(open(redir_stdin, 0), 1); 98 | } 99 | if (t) { 100 | dup2(t, 1); /* replace stdout with t */ 101 | close(t); 102 | } 103 | if (redir_stdout) { 104 | close(1); 105 | err(creat(redir_stdout, 438), 1); /* replace stdout with redir_stdout */ 106 | } 107 | err(execvp(*u, u), 1); 108 | } 109 | 110 | int main() { 111 | for (;;) { 112 | prompt(); 113 | char q[512] = {0}; /* input buffer */ 114 | char *c = q; 115 | if (fgets(c + 1, sizeof(q) - 1, stdin) == NULL) { 116 | exit(0); 117 | } 118 | /* skip to end of line */ 119 | for (; *++c;) { 120 | } 121 | run(c, 0); 122 | } 123 | } 124 | 125 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::Write; 3 | use std::io::{Error, ErrorKind}; 4 | use std::process::{Command, Stdio}; 5 | use std::{env, io}; 6 | 7 | #[derive(Debug, Clone)] 8 | enum Token { 9 | Blank, 10 | Redir(i32), 11 | Delim(bool), 12 | Normal(char), 13 | } 14 | 15 | fn token(x: Option<&char>) -> Token { 16 | match x { 17 | Some(&c) => match c { 18 | '|' => Token::Delim(true), 19 | '<' => Token::Redir(0), 20 | '>' => Token::Redir(1), 21 | ' ' | '\t' | '\n' | '\r' => Token::Blank, 22 | _ => Token::Normal(c), 23 | }, 24 | None => Token::Delim(false), 25 | } 26 | } 27 | 28 | fn run(mut it: std::iter::Peekable, output: Stdio) -> Result<(), Error> 29 | where 30 | I: Iterator, 31 | { 32 | let mut is_pipe = false; 33 | let mut args = Vec::::new(); 34 | let mut io_in = Stdio::inherit(); 35 | let mut io_out = output; 36 | while let Some(tok) = it.next() { 37 | match token(Some(&tok)) { 38 | Token::Delim(p) => { 39 | is_pipe = p; 40 | break; 41 | } 42 | Token::Normal(c) => { 43 | let mut word = String::new(); 44 | word.push(c); 45 | while let Token::Normal(c) = token(it.peek()) { 46 | it.next(); 47 | word.push(c); 48 | } 49 | args.push(word.chars().rev().collect::()); 50 | } 51 | Token::Redir(fd) => match args.pop() { 52 | Some(path) => match fd { 53 | 0 => io_in = Stdio::from(File::open(path)?), 54 | 1 => io_out = Stdio::from(File::create(path)?), 55 | _ => return Err(Error::new(ErrorKind::Other, "bad redirection fd")), 56 | }, 57 | None => { 58 | return Err(Error::new( 59 | ErrorKind::Other, 60 | "redirection filename expected", 61 | )); 62 | } 63 | }, 64 | Token::Blank => {} 65 | } 66 | } 67 | if args.is_empty() { 68 | return Ok(()); 69 | } 70 | args.reverse(); 71 | if args[0] == "cd" { 72 | let path = args 73 | .into_iter() 74 | .nth(1) 75 | .unwrap_or(env::var("HOME").unwrap_or("/".to_string())); 76 | env::set_current_dir(path)?; 77 | return Ok(()); 78 | } 79 | if is_pipe { 80 | io_in = Stdio::piped() 81 | } 82 | let mut args_iter = args.iter(); 83 | let pathname = args_iter.next().unwrap(); 84 | let mut child = Command::new(pathname) 85 | .args(args_iter) 86 | .stdin(io_in) 87 | .stdout(io_out) 88 | .spawn()?; 89 | if is_pipe { 90 | run(it, Stdio::from(child.stdin.take().unwrap()))?; 91 | } 92 | child.wait()?; 93 | Ok(()) 94 | } 95 | 96 | fn main() { 97 | loop { 98 | print!("$ "); 99 | let _ = io::stdout().flush(); // continue even if flush fails 100 | let mut input = String::new(); 101 | match io::stdin().read_line(&mut input) { 102 | Ok(0) => return, 103 | Ok(_) => { 104 | if let Err(e) = run(input.chars().rev().peekable(), Stdio::inherit()) { 105 | println!("error: {}", e); 106 | } 107 | } 108 | Err(e) => { 109 | println!("io error: {}", e); 110 | return; 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /orig/tbr.hint.txt: -------------------------------------------------------------------------------- 1 | Best Utility: 2 | 3 | Byron Rakitzis Sean Dorward 4 | Princeton University Princeton University 5 | 5707 Old Lodge Dr. 10274 Burleigh Cottage Lane 6 | Houston, TX 77066 Ellicott City, MD 21043 7 | USA USA 8 | 9 | Judges' comments: 10 | 11 | This program implements a subject a well known Un*x utility whose 12 | original source was considered to be extremely obfuscated by many 13 | people, excluding its author. In fact, this utility one a major 14 | inspiration for the formation of this contest. 15 | 16 | The author supplied us with a slightly smaller unformatted version 17 | of the program which we include below: 18 | 19 | #define D ,close( 20 | char*c,q[512],m[256],*v[99],**u,*i[3];int f[2],p;main(){for(m[m[60]=m[62]= 21 | 32]=m[*m=124[m]=9]=6;e(-8),gets(1+(c=q))||exit(0);r(0,0))for(;*++c;);} 22 | r(t,o){*i=i[2]=0;for(u=v+98;m[*--c]^9;m[*c]&32?i[*c&2]= 23 | *u,u-v^98&&++u:3)if(!m[*c]){for(*++c=0;!m[*--c];);*--u= 24 | ++c;}u-v^98?strcmp(*u,"cd")?*c?pipe(f),o=f[1]:1,(p=fork())?e(p),o? 25 | r(o,0)D o)D*f):4,wait(0):(o?dup2(*f,0)D*f)D o):*i?1 D 26 | 0),e(open(*i,0)):5,t?dup2(t,1)D t):i[2]?9 D 27 | 1),e(creat(i[2],438)):2,e(execvp(*u,u))):e(chdir(u[1])*2):6;} 28 | e(x){x<0?write(2,"?\n$ "-x/4,2),x+1||exit(1):5;} 29 | 30 | Selected notes from the author: (rot13 to read) 31 | 32 | Guvf cebtenz vf n ehqvzragnel furyy. Vg qbrf v/b erqverpgvba, cvcrf 33 | naq pq. Vg syntf reebef ba snvyrq puqve'f, bcra'f, perng'f 34 | rkrpic'f, sbex'f naq n srj flagnk reebef. 35 | 36 | Guvf cebtenz vf boshfpngrq va n srj abgnoyr jnlf: ncneg sebz gur 37 | ynlbhg (na hasbeznggrq (ohg pehapurq) irefvba vf vapyhqrq sbe 38 | crbcyr jub jnag gb chg guvf guebhtu po) vg znxrf pyrire hfr bs n 39 | jevgr fgngrzrag, fb gung gur fnzr fgngrzrag pna or hfrq gb cevag 40 | reebef naq gur cebzcg. Ol pnyyvat gur reebe shapgvba jvgu gur inyhr 41 | -8, gur cbvagre bssfrg va gur rkcerffvba "?\a$ "-k/4 tbrf sebz 0 gb 42 | 2. Cerfgb! N cebzcg. Sbe reebef jvgu ahzoref fznyyre guna -4 43 | (v.r., HAVK flfgrz pnyyf) n dhrfgvba znex vf cevagrq. 44 | 45 | Gur reebe inyhr bs puqve vf qbhoyrq fb gung jr qba'g rkvg sebz gur 46 | cnerag furyy ba n puqve reebe (fvapr r() rkvgf ba -1 reebef bayl). 47 | Nyy bgure flfgrz pnyy snvyherf rkvg fvapr gurl ner sebz fhofuryyf. 48 | 49 | Erphefvba vf farnxvyl rzcyblrq gb nibvq n frpbaq pnyy gb sbex(), 50 | naq gur yvar vf cnefrq va n snveyl ovmneer snfuvba: onpxjneqf. Gur 51 | urneg bs gur cebtenz, gung vf, gur cneg juvpu cresbezf nyy sbexf, 52 | rkrpf, bcraf, rgp. vf BAR P FGNGRZRAG. 53 | 54 | Gur zrgn-inyhrf neenl vf vavgvnyvmrq va n ovmneer snfuvba, naq gur 55 | fhofrdhrag purpxf sbe gur '<' naq '>' ner cresbezrq va n fvatyr 56 | fgngrzrag hfvat n znfx, fvapr lbh xabj gung '>'&2 vf 0, jurernf 57 | '<'&2 vf 2. Bgure fhpu zvpeb-boshfpngvbaf nobhaq. 58 | 59 | Svanyyl, vg vf abgnoyr gung gur pbqr jnf unpxrq sbe zvavznyvgl. Vs 60 | lbh ybbx ng gur pbzcerffrq irefvba, lbh jvyy or uneq-cerffrq gb 61 | ryvzvangr zber guna n srj punenpgref (jr pna'g frr ubj gb znxr vg 62 | nal fznyyre!). 550 punenpgref vf cerggl yrna sbe n furyy gung qbrf 63 | guvf zhpu. 64 | 65 | OHTF 66 | 67 | Gur flagnk bs gur furyy unf abg orra shyyl rkcyberq, ohg vs lbh gel 68 | gb erqverpg va gur fnzr qverpgvba zber guna bapr, bayl bar 69 | erqverpgvba vf cresbezrq. Guvf vf n "srngher" bs gur jnl gur yvar 70 | vf cnefrq; n cbvagre gb gur fgnpx bs nethzragf vf nffvtarq naq na 71 | nethzrag vf fgbyra rirel gvzr n ">" be "<" vf rapbhagrerq. Gur 72 | furyy syntf na reebe vs ab nethzragf ner ba gur fgnpx. Guhf, sbe 73 | rknzcyr: 74 | png > sbb > one 75 | pngf gb sbb, fvapr vg jnf chfurq ynfg, ohg 76 | png > > sbb one 77 | pngf gb one, fvapr one jnf chfurq haqre sbb. (erzrzore jr'er 78 | cnefvat evtug-yrsg) 79 | 80 | Qrcraqvat ba lbhe synibe bs HA*K, pq jvgubhg na nethzrag jvyy 81 | rvgure cebqhpr na reebe be whfg qb abguvat. 82 | 83 | Gurer vf whfg bar reebe zrffntr, gur dhrfgvba znex, ohg url, gung'f 84 | nyy rq qbrf gbb. 85 | 86 | Copyright (c) 1990, Landon Curt Noll & Larry Bassel. 87 | All Rights Reserved. Permission for personal, educational or non-profit use is 88 | granted provided this this copyright and notice are included in its entirety 89 | and remains unaltered. All other uses must receive prior permission in writing 90 | from both Landon Curt Noll and Larry Bassel. 91 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------