├── Dockerfile ├── requirements.txt ├── .Dockerignore ├── safety ├── Dockerfile ├── view.html └── hello.py ├── hello.py ├── templates └── view.html ├── README.md ├── quotes.txt └── LICENSE /Dockerfile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.1.0 2 | -------------------------------------------------------------------------------- /.Dockerignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .Dockerignore 3 | venv/ 4 | .gitignore 5 | .git/ 6 | README.md 7 | -------------------------------------------------------------------------------- /safety/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:slim-buster 2 | 3 | WORKDIR /app 4 | 5 | COPY requirements.txt /app 6 | 7 | RUN pip install --trusted-host pypi.python.org -r requirements.txt 8 | 9 | COPY . /app 10 | 11 | EXPOSE 80 12 | 13 | ENTRYPOINT [ "python" ] 14 | 15 | CMD [ "./hello.py" ] 16 | -------------------------------------------------------------------------------- /safety/view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Quote of The Day 4 | 5 | 35 | 36 | 37 |
38 |

Hello {{name}}!

39 |

Here is an interesting quote for you:

40 |

"{{quote}}"

41 |

--{{author}}

42 |
43 | 44 | 45 | -------------------------------------------------------------------------------- /hello.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, flash, redirect, render_template, request, session, abort 2 | from random import choice 3 | import json 4 | 5 | app = Flask(__name__) 6 | 7 | def read_quotes(filename): 8 | with open('quotes.txt') as f: 9 | lines = (l.strip() for l in f) 10 | return [json.loads(l) for l in lines if l] 11 | 12 | @app.route("/") 13 | def index(): 14 | return "Nigel's Container Intro Workshop. Append /hello/$your_name to the url." 15 | 16 | # @app.route("/hello/") 17 | @app.route("/hello//") 18 | def hello(name): 19 | quotes = read_quotes('quotes.txt') 20 | authors = list(set(author for _, author in quotes)) 21 | quote, _ = choice(quotes) 22 | author = choice(authors) 23 | return render_template( 24 | 'view.html', **locals()) 25 | 26 | if __name__ == "__main__": 27 | app.run(host='0.0.0.0', port=80) 28 | -------------------------------------------------------------------------------- /templates/view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Quote of The Day 4 | 5 | 35 | 36 | 37 |
38 |

Hello {{name}}!

39 |

Here is an interesting quote for you:

40 |

"{{quote}}"

41 |

--{{author}}

42 |
43 | 44 | 45 | -------------------------------------------------------------------------------- /safety/hello.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, flash, redirect, render_template, request, session, abort 2 | from random import choice 3 | import json 4 | 5 | app = Flask(__name__) 6 | 7 | def read_quotes(filename): 8 | with open('quotes.txt') as f: 9 | lines = (l.strip() for l in f) 10 | return [json.loads(l) for l in lines if l] 11 | 12 | @app.route("/") 13 | def index(): 14 | return "Nigel's Container Intro Workshop. Append /hello/$your_name to the url." 15 | 16 | # @app.route("/hello/") 17 | @app.route("/hello//") 18 | def hello(name): 19 | quotes = read_quotes('quotes.txt') 20 | authors = list(set(author for _, author in quotes)) 21 | quote, _ = choice(quotes) 22 | author = choice(authors) 23 | return render_template( 24 | 'view.html', **locals()) 25 | 26 | if __name__ == "__main__": 27 | app.run(host='0.0.0.0', port=80) 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Developer's Introduction to Containers 2 | 3 | Welcome to a Developer's Introduction to Containers. 4 | 5 | By the end of the workshop you will have acheived three outcomes: 6 | 1. You'll understand what containers are and how they came onto the scene 7 | 2. You'll be able to containerize an application and run it locally 8 | 3. You'll be able to deploy your container image to a remote registry. 9 | 10 | To complete this workshop, you will need to have Docker installed on your machine as well as an account on Docker Hub. 11 | 12 | ## Part 1: What are containers and how did they get here? 13 | 14 | #### The what: 15 | 16 | If there are two words that come to mind when you think containers, they should be **process isolation**. 17 | 18 | > “Put most simply, a process is an instance of an executing program...processes are the entities among which the kernel must share the various resources of the computer.” Michael Kerrisk, _The Linux Programming Interface_ 19 | 20 | A **container** is a process, or group of processes running in isolation. This isolation is achieved by leveraging several features of the Linux kernel. Two of the main features are **namespaces** and **cgroups**. 21 | 22 | > "A namespace wraps global system resources in an abstraction that makes it appear to the process within the namespace that they have their own instance of the resource." _namespaces man page_ 23 | 24 | A metaphor I like for this concept are apartments in an apartment building. Utilities come in to the apartment building, but it appears to each apartment that they have their own instance. In our usecase, the utilities represent resources like the network, the process id counter, and more. 25 | 26 | > "Control groups, usually referred to as cgroups, are a Linux feature which allow processes to be organized into hierarchical groups whose usage of various types of resources can then be limited and monitored." _cgroups man page_ 27 | 28 | One use of cgroups is assigning a maximum amount of resources each group can allocate to ensure that your critical system processes always have the resources they need. 29 | 30 | #### The how: 31 | 32 | Containers are not a particularly new technology. They fall under a class of virtualization called Operating System Level Virtualization. It's possible you're already familiar with some other iteration of this technology. We'll touch on some of the more notable points: 33 | 34 | Unix in 1982 had a feature called chroot which allows the "root" directory to be changed. This had an effect of isolation, but for security, it is rarely the best choice. The first major point we have for commercial adoption of what came to be known as containerization was from Virtuozzo's release in 2000. The next point of note is the concept of Zones which came from the Solaris operating system in 2005. It's notable that the term "container" most likely came from Solaris. The widespread adoption, and, anecdotally, the first interaction with containers came with Linux Containers or lxc in 2008. When Docker came on the scene in 2013, they weren't creating new technology per se, but making it easier and more secure to leverage containers for today's workloads. In fact, Docker's initial releases used lxc before they wrote their own implementation. 35 | 36 | The software Docker created to interact with the Linux kernel was packaged into a library called libcontainer. For standardization and to further encourage the development of containerization technology, Docker donated libcontainer to the Cloud Native Computing Foundation (CNCF) to start the Open Container Initiative (OCI). 37 | 38 | ## Part 2: Containerize an application and run it locally 39 | 40 | In this section, we'll use a minimal Python application to demonstrate how to containerize an application. This one is written by my friend Mofi Rahman and it greets a website visitor by name and then provides them a quote of the day. After containerizing, you are strongly encouraged to customize the application. 41 | 42 | Make sure you get a copy of the repository locally by cloning it with Git. 43 | 44 | `git clone https://github.com/pnbrown/containers-intro` 45 | 46 | ### The application 47 | 48 | We chose Python as an accessible language for participants. There are four files that comprise the application: `hello.py`, `quotes.txt`,`requirements.txt`, and `templates/view.html` which contain our web server, list of quotes, dependencies, and the web page respectively. 49 | 50 | When a user visits our site at the root url, they'll see text defined in our `hello.py` server. If they then append `/hello/$your_name` they will get to the page defined in `templates/view.html` which will show them a random quote from `quotes.txt`. 51 | 52 | If you have a local Python 3 installation and want to run the application before containerizing, you may by following these steps after navigating to the project directory: 53 | 54 | 1. First install the dependencies, which, in this case, is Flask 1.1.1 55 | 56 | `pip install --trusted-host pypi.python.org -r requirements.txt` 57 | 58 | 2. Start the application: 59 | 60 | `python hello.py` 61 | 62 | ### Writing a Dockerfile 63 | 64 | In the world of containers, it's helpful to know the difference between a _container_, an _image_, and a _registry_. We mentioned earlier that a container is a process or group of processes _running_ in isolation. But what about when the process(es) are not running? 65 | 66 | Containers are built from a set of instructions. Commonly, the instructions are contained in a text file called a Dockerfile. From these instructions are built an _image_. Images are stored in _registries_ until they're ready to be run. You can think of an image as a recipe and the required ingredients and the container as our cooked meal while registries would be the cookbooks in which we keep our recipes. 67 | 68 | So now let's gather our ingredients and write our recipe. 69 | 70 | You're going to need to edit the empty Dockerfile in the root directory. 71 | 72 | Container images are created in modular layers. Generally, each line in a Dockerfile creates a new layer that builds upon the one immediately preceding it. The unique hash for each layer is then calculated and cataloged. In practice, this speeds up subsequent container builds because the modular layers contained in our images are reused whenever possible. This means that the first builds will generally take some time, but each subsequent build completes much faster. Further, you should ensure that the lines of the Dockerfile most likely to change are toward the bottom to ensure speedy builds. Docker will only rebuild the image from the line that changed to the end of the file. 73 | 74 | 75 | 76 | 1. The first line of our Dockerfile defines a base image. We're using one created by the Python organization that uses the Buster operating system: 77 | 78 | `FROM python:slim-buster` 79 | 80 | 2. The second line creates and sets our working directory for the image for any of the subsequent adding, copying, or running of files: 81 | 82 | `WORKDIR /app` 83 | 84 | 3. The third line copies our requirements into our working directory: 85 | 86 | `COPY requirements.txt /app` 87 | 88 | 4. The fourth line installs our dependencies that Python will need. By using the image that the Python organization created, we can ensure that everything Python needs to run is already a part of our image: 89 | 90 | `RUN pip install --trusted-host pypi.python.org -r requirements.txt` 91 | 92 | 5. The fifth line copies the rest of our current directory into the working directory so we can access all of our files once the container is running: 93 | 94 | `COPY . /app` 95 | 96 | 6. The sixth line indicates on which ports Docker should listen when our application is running. This Flask app runs on port 80 so we'll expose that: 97 | 98 | `EXPOSE 80` 99 | 100 | 7. The seventh line determines the entry point for the running container. After the container is built, it runs the entrypoint command. Ours will be python: 101 | 102 | `ENTRYPOINT [ "python" ]` 103 | 104 | 8. The eigth line sets the command that is provided to the entrypoint. For our purposes, we want to run the hello.py file we copied over: 105 | 106 | `CMD ["./hello.py"]` 107 | 108 | Your Dockerfile should look like the example below: 109 | 110 | ``` 111 | FROM python:slim-buster 112 | 113 | WORKDIR /app 114 | 115 | COPY requirements.txt /app 116 | 117 | RUN pip install --trusted-host pypi.python.org -r requirements.txt 118 | 119 | COPY . /app 120 | 121 | EXPOSE 80 122 | 123 | ENTRYPOINT [ "python" ] 124 | 125 | CMD [ "./hello.py" ] 126 | ``` 127 | 128 | In case something has gone wrong, there is a completed Dockerfile in the safety directory that you can use. 129 | 130 | ### Building our Docker image 131 | 132 | We wrote the recipe for our container and now we need to assemble the ingredients through the building of the container image. The Docker engine will go line by line of our Dockerfile and assemble it. If you have an account on Docker Hub, please use that when you name your image. You should use the tag for version control. Use whatever versioning or tag makes sense for you. 133 | 134 | ``` 135 | docker build -t /: . 136 | ``` 137 | 138 | ### Running our image locally 139 | 140 | Now that we've built our image, we can run it locally and see our process(es) running in isolation. We need to map that port we exposed in our Dockerfile to one that's not currently in use by our system. I often use port 4567. That is reflected in the command below. The `-p` flag handles the port mapping in the form host_port:container_port. Additionally, you can use the `-d` flag to run the container in the background or detached mode. 141 | 142 | `docker run -p 4567:80 /:` 143 | 144 | 145 | ## Part 3: Deploy your image to a remote registry 146 | 147 | When we've built our container, it get stored in the local container registry on our machine. You can see all the images currently in our local registry (cookbook) with the `docker images` command. Some recipes are too good to keep to ourselves. We can share it by publishing it to a remote registry. For our case, we'll share it to Docker Hub. 148 | 149 | ### Push it to Docker Hub 150 | 151 | We refer to putting images in repositories as "pushing" them. Once you log into your Docker account, you can then push your image to your repository. Once it's there, anyone can "pull" your image to their local registry and run it. 152 | 153 | ``` 154 | docker login 155 | docker push /: 156 | ``` 157 | -------------------------------------------------------------------------------- /quotes.txt: -------------------------------------------------------------------------------- 1 | ["Life isn’t about getting and having, it’s about giving and being.", "Kevin Kruse"] 2 | ["Whatever the mind of man can conceive and believe, it can achieve.", "Napoleon Hill"] 3 | ["Strive not to be a success, but rather to be of value.", "Albert Einstein"] 4 | ["Two roads diverged in a wood, and I—I took the one less traveled by, And that has made all the difference.", "Robert Frost"] 5 | ["I attribute my success to this: I never gave or took any excuse.", "Florence Nightingale"] 6 | ["You miss 100% of the shots you don’t take.", "Wayne Gretzky"] 7 | ["I’ve missed more than 9000 shots in my career. I’ve lost almost 300 games. 26 times I’ve been trusted to take the game winning shot and missed. I’ve failed over and over and over again in my life. And that is why I succeed.", "Michael Jordan"] 8 | ["The most difficult thing is the decision to act, the rest is merely tenacity.", "Amelia Earhart"] 9 | ["Every strike brings me closer to the next home run.", "Babe Ruth"] 10 | ["Definiteness of purpose is the starting point of all achievement.", "W. Clement Stone"] 11 | ["We must balance conspicuous consumption with conscious capitalism.", "Kevin Kruse"] 12 | ["Life is what happens to you while you’re busy making other plans.", "John Lennon"] 13 | ["We become what we think about.", "Earl Nightingale"] 14 | ["14.Twenty years from now you will be more disappointed by the things that you didn’t do than by the ones you did do, so throw off the bowlines, sail away from safe harbor, catch the trade winds in your sails. Explore, Dream, Discover.", "Mark Twain"] 15 | ["15.Life is 10% what happens to me and 90% of how I react to it.", "Charles Swindoll"] 16 | ["The most common way people give up their power is by thinking they don’t have any.", "Alice Walker"] 17 | ["The mind is everything. What you think you become.", "Buddha"] 18 | ["The best time to plant a tree was 20 years ago. The second best time is now.", "Chinese Proverb"] 19 | ["An unexamined life is not worth living.", "Socrates"] 20 | ["Eighty percent of success is showing up.", "Woody Allen"] 21 | ["Your time is limited, so don’t waste it living someone else’s life.", "Steve Jobs"] 22 | ["Winning isn’t everything, but wanting to win is.", "Vince Lombardi"] 23 | ["I am not a product of my circumstances. I am a product of my decisions.", "Stephen Covey"] 24 | ["Every child is an artist. The problem is how to remain an artist once he grows up.", "Pablo Picasso"] 25 | ["You can never cross the ocean until you have the courage to lose sight of the shore.", "Christopher Columbus"] 26 | ["I’ve learned that people will forget what you said, people will forget what you did, but people will never forget how you made them feel.", "Maya Angelou"] 27 | ["Either you run the day, or the day runs you.", "Jim Rohn"] 28 | ["Whether you think you can or you think you can’t, you’re right.", "Henry Ford"] 29 | ["The two most important days in your life are the day you are born and the day you find out why.", "Mark Twain"] 30 | ["Whatever you can do, or dream you can, begin it. Boldness has genius, power and magic in it.", "Johann Wolfgang von Goethe"] 31 | ["The best revenge is massive success.", "Frank Sinatra"] 32 | ["People often say that motivation doesn’t last. Well, neither does bathing. That’s why we recommend it daily.", "Zig Ziglar"] 33 | ["Life shrinks or expands in proportion to one’s courage.", "Anais Nin"] 34 | ["If you hear a voice within you say “you cannot paint,” then by all means paint and that voice will be silenced.", "Vincent Van Gogh"] 35 | ["There is only one way to avoid criticism: do nothing, say nothing, and be nothing.", "Aristotle"] 36 | ["Ask and it will be given to you; search, and you will find; knock and the door will be opened for you.", "Jesus"] 37 | ["The only person you are destined to become is the person you decide to be.", "Ralph Waldo Emerson"] 38 | ["Go confidently in the direction of your dreams. Live the life you have imagined.", "Henry David Thoreau"] 39 | ["When I stand before God at the end of my life, I would hope that I would not have a single bit of talent left and could say, I used everything you gave me.", "Erma Bombeck"] 40 | ["Few things can help an individual more than to place responsibility on him, and to let him know that you trust him.", "Booker T. Washington"] 41 | ["Certain things catch your eye, but pursue only those that capture the heart.", " Ancient Indian Proverb"] 42 | ["Believe you can and you’re halfway there.", "Theodore Roosevelt"] 43 | ["Everything you’ve ever wanted is on the other side of fear.", "George Addair"] 44 | ["We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light.", "Plato"] 45 | ["Teach thy tongue to say, “I do not know,” and thous shalt progress.", "Maimonides"] 46 | ["Start where you are. Use what you have. Do what you can.", "Arthur Ashe"] 47 | ["When I was 5 years old, my mother always told me that happiness was the key to life. When I went to school, they asked me what I wanted to be when I grew up. I wrote down ‘happy’. They told me I didn’t understand the assignment, and I told them they didn’t understand life.", "John Lennon"] 48 | ["Fall seven times and stand up eight.", "Japanese Proverb"] 49 | ["When one door of happiness closes, another opens, but often we look so long at the closed door that we do not see the one that has been opened for us.", "Helen Keller"] 50 | ["Everything has beauty, but not everyone can see.", "Confucius"] 51 | ["How wonderful it is that nobody need wait a single moment before starting to improve the world.", "Anne Frank"] 52 | ["When I let go of what I am, I become what I might be.", "Lao Tzu"] 53 | ["Life is not measured by the number of breaths we take, but by the moments that take our breath away.", "Maya Angelou"] 54 | ["Happiness is not something readymade. It comes from your own actions.", "Dalai Lama"] 55 | ["If you’re offered a seat on a rocket ship, don’t ask what seat! Just get on.", "Sheryl Sandberg"] 56 | ["First, have a definite, clear practical ideal; a goal, an objective. Second, have the necessary means to achieve your ends; wisdom, money, materials, and methods. Third, adjust all your means to that end.", "Aristotle"] 57 | ["If the wind will not serve, take to the oars.", "Latin Proverb"] 58 | ["You can’t fall if you don’t climb. But there’s no joy in living your whole life on the ground.", "Unknown"] 59 | ["We must believe that we are gifted for something, and that this thing, at whatever cost, must be attained.", "Marie Curie"] 60 | ["Too many of us are not living our dreams because we are living our fears.", "Les Brown"] 61 | ["Challenges are what make life interesting and overcoming them is what makes life meaningful.", "Joshua J. Marine"] 62 | ["If you want to lift yourself up, lift up someone else.", "Booker T. Washington"] 63 | ["I have been impressed with the urgency of doing. Knowing is not enough; we must apply. Being willing is not enough; we must do.", "Leonardo da Vinci"] 64 | ["Limitations live only in our minds. But if we use our imaginations, our possibilities become limitless.", "Jamie Paolinetti"] 65 | ["You take your life in your own hands, and what happens? A terrible thing, no one to blame.", "Erica Jong"] 66 | ["What’s money? A man is a success if he gets up in the morning and goes to bed at night and in between does what he wants to do.", "Bob Dylan"] 67 | ["I didn’t fail the test. I just found 100 ways to do it wrong.", "Benjamin Franklin"] 68 | ["In order to succeed, your desire for success should be greater than your fear of failure.", "Bill Cosby"] 69 | ["A person who never made a mistake never tried anything new.", " Albert Einstein"] 70 | ["The person who says it cannot be done should not interrupt the person who is doing it.", "Chinese Proverb"] 71 | ["There are no traffic jams along the extra mile.", "Roger Staubach"] 72 | ["It is never too late to be what you might have been.", "George Eliot"] 73 | ["You become what you believe.", "Oprah Winfrey"] 74 | ["I would rather die of passion than of boredom.", "Vincent van Gogh"] 75 | ["A truly rich man is one whose children run into his arms when his hands are empty.", "Unknown"] 76 | ["It is not what you do for your children, but what you have taught them to do for themselves, that will make them successful human beings.", "Ann Landers"] 77 | ["If you want your children to turn out well, spend twice as much time with them, and half as much money.", "Abigail Van Buren"] 78 | ["Build your own dreams, or someone else will hire you to build theirs.", "Farrah Gray"] 79 | ["The battles that count aren’t the ones for gold medals. The struggles within yourself–the invisible battles inside all of us–that’s where it’s at.", "Jesse Owens"] 80 | ["Education costs money. But then so does ignorance.", "Sir Claus Moser"] 81 | ["I have learned over the years that when one’s mind is made up, this diminishes fear.", "Rosa Parks"] 82 | ["It does not matter how slowly you go as long as you do not stop.", "Confucius"] 83 | ["If you look at what you have in life, you’ll always have more. If you look at what you don’t have in life, you’ll never have enough.", "Oprah Winfrey"] 84 | ["Remember that not getting what you want is sometimes a wonderful stroke of luck.", "Dalai Lama"] 85 | ["You can’t use up creativity. The more you use, the more you have.", "Maya Angelou"] 86 | ["Dream big and dare to fail.", "Norman Vaughan"] 87 | ["Our lives begin to end the day we become silent about things that matter.", "Martin Luther King Jr."] 88 | ["Do what you can, where you are, with what you have.", "Teddy Roosevelt"] 89 | ["If you do what you’ve always done, you’ll get what you’ve always gotten.", "Tony Robbins"] 90 | ["Dreaming, after all, is a form of planning.", "Gloria Steinem"] 91 | ["It’s your place in the world; it’s your life. Go on and do all you can with it, and make it the life you want to live.", "Mae Jemison"] 92 | ["You may be disappointed if you fail, but you are doomed if you don’t try.", "Beverly Sills"] 93 | ["Remember no one can make you feel inferior without your consent.", "Eleanor Roosevelt"] 94 | ["Life is what we make it, always has been, always will be.", "Grandma Moses"] 95 | ["The question isn’t who is going to let me; it’s who is going to stop me.", "Ayn Rand"] 96 | ["When everything seems to be going against you, remember that the airplane takes off against the wind, not with it.", "Henry Ford"] 97 | ["It’s not the years in your life that count. It’s the life in your years.", "Abraham Lincoln"] 98 | ["Change your thoughts and you change your world.", "Norman Vincent Peale"] 99 | ["Either write something worth reading or do something worth writing.", "Benjamin Franklin"] 100 | ["Nothing is impossible, the word itself says, “I’m possible!”", "–Audrey Hepburn"] 101 | ["The only way to do great work is to love what you do.", "Steve Jobs"] 102 | ["If you can dream it, you can achieve it.", "Zig Ziglar"] -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------