├── .gitignore ├── test ├── Dockerfile ├── test.sh ├── wait-for-it.sh └── sh2ju.sh ├── healthcheck.sh ├── etc ├── afp.conf └── avahi │ └── services │ └── afpd.service ├── hooks ├── build └── env ├── docker-compose.test.yml ├── .circleci └── config.yml ├── start.sh ├── README.md ├── Dockerfile └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | results/ 2 | -------------------------------------------------------------------------------- /test/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.8 2 | 3 | COPY *.sh ./ 4 | CMD ["./test.sh"] 5 | 6 | -------------------------------------------------------------------------------- /healthcheck.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | mkdir -p /tmp/afptest 4 | mount_afp "afp://timecapsule:timecapsule@localhost/Time Capsule" /tmp/afptest 5 | sleep 3 6 | umount /tmp/afptest 7 | 8 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./wait-for-it.sh timecapsule:548 4 | 5 | source /sh2ju.sh 6 | juLogClean 7 | 8 | juLog -name="opentcp" nc -zv -w 10 timecapsule 548 9 | 10 | -------------------------------------------------------------------------------- /etc/afp.conf: -------------------------------------------------------------------------------- 1 | [Global] 2 | log file = /tmp/log 3 | 4 | [Time Capsule] 5 | path = /backup 6 | appledouble = ea 7 | vol size limit = 0 8 | ea = auto 9 | time machine = yes 10 | 11 | -------------------------------------------------------------------------------- /hooks/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | 3 | . ./hooks/env 4 | 5 | docker build --build-arg "SOURCE_COMMIT=$GIT_SHA1" --build-arg "DOCKERFILE_PATH=$DOCKERFILE_PATH" --build-arg "SOURCE_TYPE=$SOURCE_TYPE" -t $IMAGE_NAME . 6 | -------------------------------------------------------------------------------- /docker-compose.test.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | timecapsule: 5 | build: . 6 | 7 | sut: 8 | build: test 9 | links: 10 | - timecapsule 11 | volumes: 12 | - ./test/results:/results 13 | -------------------------------------------------------------------------------- /etc/avahi/services/afpd.service: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %h 5 | 6 | _afpovertcp._tcp 7 | 548 8 | 9 | 10 | _device-info._tcp 11 | 0 12 | model=TimeCapsule 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /hooks/env: -------------------------------------------------------------------------------- 1 | # These values are passed by the hub, but if they aren't we can get them from git. 2 | [ -n "$SOURCE_BRANCH" ] || SOURCE_BRANCH=$(git symbolic-ref -q --short HEAD) 3 | [ -n "$SOURCE_BRANCH" ] || SOURCE_BRANCH=latest 4 | [ -n "$GIT_SHA1" ] || GIT_SHA1=$(git rev-parse -q HEAD) 5 | 6 | [ "$SOURCE_BRANCH" = "master" ] && SOURCE_BRANCH="latest" 7 | 8 | # Set defaults for build arguments 9 | [ -n "$SOURCE_TYPE" ] || SOURCE_TYPE=git 10 | [ -n "$DOCKERFILE_PATH" ] || DOCKERFILE_PATH=. 11 | [ -n "$IMAGE_NAME" ] || IMAGE_NAME=pdouble16/timecapsule:$SOURCE_BRANCH 12 | 13 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | working_directory: /home/build 5 | docker: 6 | - image: circleci/buildpack-deps:bionic-curl 7 | user: root 8 | 9 | steps: 10 | - checkout 11 | 12 | - setup_remote_docker 13 | 14 | - run: 15 | name: Docker Build 16 | command: ./hooks/build 17 | 18 | - run: 19 | name: Short Test 20 | command: | 21 | . ./hooks/env 22 | mkdir -p ./test/results 23 | docker-compose -f docker-compose.test.yml build sut 24 | docker-compose -f docker-compose.test.yml run sut 25 | -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | test -n "${VOLPATH}" || VOLPATH="/backup" 4 | 5 | # Adjust user/group 6 | sed -i -e "s/:1000:1000:/:${PUID:-1000}:${PGID:-1000}:/" /etc/passwd 7 | 8 | # Configure netatalk 9 | sed -i -e "s/vol size limit = 0/vol size limit = ${VOLSIZELIMIT:-500000}/" /etc/afp.conf 10 | sed -i -e "s:path = /backup:path = ${VOLPATH}:" /etc/afp.conf 11 | cat /etc/afp.conf 12 | 13 | # Fix backup permissions 14 | mkdir -p ${VOLPATH} || exit 1 15 | find ${VOLPATH} -not \( -user timecapsule -a -group timecapsule \) -exec chown timecapsule:timecapsule {} + 16 | find ${VOLPATH} -type d -a -not -perm -0770 -exec chmod ug+rwx {} + 17 | 18 | mkdir -p /var/run/dbus 19 | rm -f /var/run/dbus.pid 20 | /usr/bin/dbus-uuidgen --ensure=/etc/machine-id 21 | /usr/bin/dbus-daemon --system 22 | 23 | rm -f /var/run/avahi-daemon/pid 24 | /usr/sbin/avahi-daemon --no-chroot -D 25 | 26 | rm -f /tmp/log 27 | mkfifo /tmp/log 28 | 29 | /sbin/netatalk 30 | 31 | cat /tmp/log 32 | 33 | killall netatalk 34 | /usr/sbin/avahi-daemon -k 35 | killall dbus-daemon 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | timecapsule [![CircleCI](https://circleci.com/gh/double16/timecapsule.svg?style=svg&circle-token=6060fdc30159f0f2ec2ca16dfbc0861e843e50e9)](https://circleci.com/gh/double16/timecapsule) 2 | =========== 3 | 4 | [![](https://images.microbadger.com/badges/image/pdouble16/timecapsule.svg)](http://microbadger.com/images/pdouble16/timecapsule "Get your own image badge on microbadger.com") [![](https://images.microbadger.com/badges/version/pdouble16/timecapsule.svg)](http://microbadger.com/images/pdouble16/timecapsule "Get your own version badge on microbadger.com") [![](https://images.microbadger.com/badges/commit/pdouble16/timecapsule.svg)](http://microbadger.com/images/pdouble16/timecapsule "Get your own version badge on microbadger.com") [![](https://images.microbadger.com/badges/license/pdouble16/timecapsule.svg)](http://microbadger.com/images/pdouble16/timecapsule "Get your own version badge on microbadger.com") 5 | 6 | Supports Apple Time Machine backup by using netatalk to look like a time capsule. 7 | 8 | Features: 9 | - Use net="host" for Bonjour support 10 | - Volume /backup to store the backup, may use a volume or host mount 11 | - VOLPATH environment variable to override /backup for backup storage 12 | - Volume size limit defaults to 500000KB (~500GB), set using VOLSIZELIMIT environment variable in KB units 13 | - PUID and PGID to (optionally) set user and group 14 | 15 | Authenticate to the Time Capsule volume using user `timecapsule` and password `timecapsule`. Due to the fixed password, do not expose this service to untrusted environments. 16 | 17 | Example `docker-compose.yml`: 18 | ```yaml 19 | version: "2" 20 | 21 | volumes: 22 | timecapsule: 23 | 24 | services: 25 | timecapsule: 26 | image: pdouble16/timecapsule:3.1.11 27 | restart: always 28 | ports: 29 | - "548:548" 30 | environment: 31 | - VOLSIZELIMIT=1000000 32 | volumes: 33 | - timecapsule:/backup 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.8 2 | 3 | ARG SOURCE_COMMIT 4 | ARG DOCKERFILE_PATH 5 | ARG SOURCE_TYPE 6 | 7 | ENV LANG=en_US.UTF-8 LC_ALL=C.UTF-8 LANGUAGE=en_US.UTF-8 VERSION=3.1.11 8 | 9 | RUN apk add --no-cache avahi build-base curl db-dev libgcrypt libgcrypt-dev file dbus afpfs-ng \ 10 | && curl --fail --location https://downloads.sourceforge.net/project/netatalk/netatalk/${VERSION}/netatalk-${VERSION}.tar.gz | tar xzf - \ 11 | && cd netatalk-${VERSION} \ 12 | && ./configure --prefix= --enable-dbus --disable-ldap --enable-quota --enable-pgp-uam \ 13 | && make \ 14 | && make test \ 15 | && make install \ 16 | && cd - && rm -rf netatalk-${VERSION} \ 17 | && apk del build-base libgcrypt-dev \ 18 | && addgroup -g 1000 timecapsule \ 19 | && adduser -u 1000 -G timecapsule -D timecapsule \ 20 | && echo "timecapsule:timecapsule" | chpasswd 21 | 22 | VOLUME [ "/backup" ] 23 | EXPOSE 548 24 | 25 | COPY etc/afp.conf /etc/ 26 | ADD etc/avahi/services/afpd.service /etc/avahi/services/afpd.service 27 | 28 | COPY start.sh healthcheck.sh / 29 | RUN chmod u+x /*.sh 30 | 31 | CMD ["/start.sh"] 32 | 33 | # Can't find package for mount_afp in Alpine Linux, afpgetstats isn't working 34 | #HEALTHCHECK CMD /healthcheck.sh || exit 1 35 | HEALTHCHECK CMD nc -zv localhost 548 || exit 1 36 | 37 | LABEL maintainer="Patrick Double " \ 38 | org.label-schema.docker.dockerfile="$DOCKERFILE_PATH/Dockerfile" \ 39 | org.label-schema.license="Apache-2.0" \ 40 | org.label-schema.name="Supports Apple Time Machine backup by using netatalk ${VERSION} to look like a Time Capsule(tm)" \ 41 | org.label-schema.url="https://github.com/double16/timecapsule" \ 42 | org.label-schema.vendor="https://github.com/double16" \ 43 | org.label-schema.vcs-ref="$SOURCE_COMMIT" \ 44 | org.label-schema.vcs-type="$SOURCE_TYPE" \ 45 | org.label-schema.vcs-url="https://github.com/double16/timecapsule.git" \ 46 | org.label-schema.vendor="https://github.com/double16" 47 | -------------------------------------------------------------------------------- /test/wait-for-it.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Use this script to test if a given TCP host/port are available 3 | 4 | cmdname=$(basename $0) 5 | 6 | echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } 7 | 8 | usage() 9 | { 10 | cat << USAGE >&2 11 | Usage: 12 | $cmdname host:port [-s] [-t timeout] [-- command args] 13 | -h HOST | --host=HOST Host or IP under test 14 | -p PORT | --port=PORT TCP port under test 15 | Alternatively, you specify the host and port as host:port 16 | -s | --strict Only execute subcommand if the test succeeds 17 | -q | --quiet Don't output any status messages 18 | -t TIMEOUT | --timeout=TIMEOUT 19 | Timeout in seconds, zero for no timeout 20 | -- COMMAND ARGS Execute command with args after the test finishes 21 | USAGE 22 | exit 1 23 | } 24 | 25 | wait_for() 26 | { 27 | if [[ $TIMEOUT -gt 0 ]]; then 28 | echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT" 29 | else 30 | echoerr "$cmdname: waiting for $HOST:$PORT without a timeout" 31 | fi 32 | start_ts=$(date +%s) 33 | while : 34 | do 35 | nc -z $HOST $PORT >/dev/null 2>&1 36 | result=$? 37 | if [[ $result -eq 0 ]]; then 38 | end_ts=$(date +%s) 39 | echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds" 40 | break 41 | fi 42 | sleep 1 43 | done 44 | return $result 45 | } 46 | 47 | wait_for_wrapper() 48 | { 49 | # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 50 | if [[ $QUIET -eq 1 ]]; then 51 | timeout -t $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & 52 | else 53 | timeout -t $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & 54 | fi 55 | PID=$! 56 | trap "kill -INT -$PID" INT 57 | wait $PID 58 | RESULT=$? 59 | if [[ $RESULT -ne 0 ]]; then 60 | echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT" 61 | fi 62 | return $RESULT 63 | } 64 | 65 | # process arguments 66 | while [[ $# -gt 0 ]] 67 | do 68 | case "$1" in 69 | *:* ) 70 | HOST=${1/:*/} 71 | PORT=${1/*:/} 72 | shift 1 73 | ;; 74 | --child) 75 | CHILD=1 76 | shift 1 77 | ;; 78 | -q | --quiet) 79 | QUIET=1 80 | shift 1 81 | ;; 82 | -s | --strict) 83 | STRICT=1 84 | shift 1 85 | ;; 86 | -h) 87 | HOST="$2" 88 | if [[ $HOST == "" ]]; then break; fi 89 | shift 2 90 | ;; 91 | --host=*) 92 | HOST="${1#*=}" 93 | shift 1 94 | ;; 95 | -p) 96 | PORT="$2" 97 | if [[ $PORT == "" ]]; then break; fi 98 | shift 2 99 | ;; 100 | --port=*) 101 | PORT="${1#*=}" 102 | shift 1 103 | ;; 104 | -t) 105 | TIMEOUT="$2" 106 | if [[ $TIMEOUT == "" ]]; then break; fi 107 | shift 2 108 | ;; 109 | --timeout=*) 110 | TIMEOUT="${1#*=}" 111 | shift 1 112 | ;; 113 | --) 114 | shift 115 | CLI="$@" 116 | break 117 | ;; 118 | --help) 119 | usage 120 | ;; 121 | *) 122 | echoerr "Unknown argument: $1" 123 | usage 124 | ;; 125 | esac 126 | done 127 | 128 | if [[ "$HOST" == "" || "$PORT" == "" ]]; then 129 | echoerr "Error: you need to provide a host and port to test." 130 | usage 131 | fi 132 | 133 | TIMEOUT=${TIMEOUT:-15} 134 | STRICT=${STRICT:-0} 135 | CHILD=${CHILD:-0} 136 | QUIET=${QUIET:-0} 137 | 138 | if [[ $CHILD -gt 0 ]]; then 139 | wait_for 140 | RESULT=$? 141 | exit $RESULT 142 | else 143 | if [[ $TIMEOUT -gt 0 ]]; then 144 | wait_for_wrapper 145 | RESULT=$? 146 | else 147 | wait_for 148 | RESULT=$? 149 | fi 150 | fi 151 | 152 | if [[ "$CLI" != "" ]]; then 153 | if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then 154 | echoerr "$cmdname: strict mode, refusing to execute subprocess" 155 | exit $RESULT 156 | fi 157 | exec $CLI 158 | else 159 | exit $RESULT 160 | fi 161 | -------------------------------------------------------------------------------- /test/sh2ju.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ### Copyright 2010 Manuel Carrasco Moñino. (manolo at apache.org) 3 | ### Copyright 2016 Patrick Double (pat at patdouble.com) 4 | ### 5 | ### Licensed under the Apache License, Version 2.0. 6 | ### You may obtain a copy of it at 7 | ### http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | ### 10 | ### A library for shell scripts which creates reports in jUnit format. 11 | ### These reports can be used in Hudson, or any other CI. 12 | ### 13 | ### Usage: 14 | ### - source this file in your shell script 15 | ### - Use juLog to call your command any time you want to produce a new report 16 | ### Usage: juLog command arguments 17 | ### options: 18 | ### -name="TestName" : the test name which will be shown in the junit report 19 | ### -error="RegExp" : a regexp which sets the test as failure when the output matches it 20 | ### -ierror="RegExp" : same as -error but case insensitive 21 | ### - Junit reports are left in the folder 'result' under the directory where the script is executed. 22 | ### - Configure hudson to parse junit files from the generated folder 23 | ### 24 | 25 | asserts=00; errors=0; total=0; content="" 26 | 27 | # create output folder 28 | juDIR=${CIRCLE_TEST_REPORTS:-`pwd`/results} 29 | mkdir -p "$juDIR" || exit 30 | 31 | # The name of the suite is calculated based in your script name 32 | suite=`basename $0 | sed -e 's/.sh$//' | tr "." "_"` 33 | 34 | # A wrapper for the eval method which allows catching seg-faults and use tee 35 | errfile=/tmp/evErr.$$.log 36 | eVal() { 37 | eval "$1" 38 | echo $? | tr -d "\n" >$errfile 39 | } 40 | 41 | # Method to clean old tests 42 | juLogClean() { 43 | echo "+++ Removing old junit reports from: $juDIR " 44 | rm -f "$juDIR"/TEST-* 45 | } 46 | 47 | # Execute a command and record its results 48 | juLog() { 49 | 50 | # parse arguments 51 | local ya="" icase="" name="" ereg="" icase="" cmd="" 52 | while [ -z "$ya" ]; do 53 | case "$1" in 54 | -name=*) name=$asserts-`echo "$1" | sed -e 's/-name=//'`; shift;; 55 | -ierror=*) ereg=`echo "$1" | sed -e 's/-ierror=//'`; icase="-i"; shift;; 56 | -error=*) ereg=`echo "$1" | sed -e 's/-error=//'`; shift;; 57 | *) ya=1;; 58 | esac 59 | done 60 | 61 | # use first arg as name if it was not given 62 | if [ -z "$name" ]; then 63 | name="$asserts-$1" 64 | fi 65 | 66 | # calculate command to eval 67 | [ -z "$1" ] && return 68 | cmd="$1"; shift 69 | while [ -n "$1" ] 70 | do 71 | cmd="$cmd \"$1\"" 72 | shift 73 | done 74 | 75 | # eval the command sending output to a file 76 | outf=/var/tmp/ju$$.txt 77 | >$outf 78 | echo "" | tee -a $outf 79 | echo "+++ Running case: $name " | tee -a $outf 80 | echo "+++ working dir: "`pwd` | tee -a $outf 81 | echo "+++ command: $cmd" | tee -a $outf 82 | ini=`date +%s` 83 | eVal "$cmd" 2>&1 | tee -a $outf 84 | evErr=`cat $errfile` 85 | rm -f $errfile 86 | end=`date +%s` 87 | echo "+++ exit code: $evErr" | tee -a $outf 88 | 89 | # set the appropriate error, based in the exit code and the regex 90 | [ $evErr != 0 ] && err=1 || err=0 91 | out=`cat $outf | sed -e 's/^\([^+]\)/| \1/g'` 92 | if [ $err = 0 -a -n "$ereg" ]; then 93 | H=`echo "$out" | egrep $icase "$ereg"` 94 | [ -n "$H" ] && err=1 95 | fi 96 | echo "+++ error: $err" | tee -a $outf 97 | rm -f $outf 98 | 99 | # calculate vars 100 | asserts=`expr $asserts + 1` 101 | asserts=`printf "%.2d" $asserts` 102 | errors=`expr $errors + $err` 103 | time=`expr $end - $ini` 104 | total=`expr $total + $time` 105 | 106 | # write the junit xml report 107 | ## failure tag 108 | [ $err = 0 ] && failure="" || failure=" 109 | 110 | " 111 | ## testcase tag 112 | content="$content 113 | 114 | $failure 115 | 116 | 119 | 120 | 121 | " 122 | ## testsuite block 123 | cat < "$juDIR/TEST-$suite.xml" 124 | 125 | $content 126 | 127 | EOF 128 | 129 | return $evErr 130 | } 131 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------