From: Thomas Goirand Date: Tue, 28 Dec 2021 07:45:18 +0000 (+0000) Subject: ceph (16.2.6+ds-11) unstable; urgency=medium X-Git-Tag: archive/raspbian/16.2.7+ds-4+rpi1~2^2^2^2~19 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=1ea66276d982d89da4e8155a07c893540101d7e5;p=ceph.git ceph (16.2.6+ds-11) unstable; urgency=medium * Revert libcephfs2.symbols "fix". [dgit import unpatched ceph 16.2.6+ds-11] --- 1ea66276d982d89da4e8155a07c893540101d7e5 diff --cc debian/.gitlab-ci.yml index 000000000,000000000..9815b7cd1 new file mode 100644 --- /dev/null +++ b/debian/.gitlab-ci.yml @@@ -1,0 -1,0 +1,14 @@@ ++include: ++ - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml ++ - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml ++ ++variables: ++ RELEASE: 'unstable' ++ SALSA_CI_DISABLE_APTLY: 0 ++ SALSA_CI_DISABLE_AUTOPKGTEST: 0 ++ SALSA_CI_DISABLE_BLHC: 0 ++ SALSA_CI_DISABLE_LINTIAN: 0 ++ SALSA_CI_DISABLE_PIUPARTS: 0 ++ SALSA_CI_DISABLE_REPROTEST: 1 ++ SALSA_CI_DISABLE_BUILD_PACKAGE_ALL: 1 ++ SALSA_CI_DISABLE_BUILD_PACKAGE_ANY: 1 diff --cc debian/README.Debian index 000000000,000000000..be21ad791 new file mode 100644 --- /dev/null +++ b/debian/README.Debian @@@ -1,0 -1,0 +1,120 @@@ ++## See online installation and setup documentation at ++ ++ http://ceph.com/docs/master/install/manual-deployment/ ++ ++-------- -------- -------- ++ ++## "systemd" requires manual activation of services: ++ ++ ## MON ++ # systemctl start ceph-mon ++ # systemctl enable ceph-mon ++ ++ ## OSD.0 (set other OSDs like this) ++ # systemctl start ceph-osd@0 ++ # systemctl enable ceph-osd@0 ++ ++ ## MDS ++ # systemctl start ceph-mds ++ # systemctl enable ceph-mds ++ ++ ## "ceph" meta-service (starts/stops all the above like old init script) ++ # systemctl start ceph ++ # systemctl enable ceph ++ ++ The ceph cluster can be set in the "/etc/default/ceph" file ++ by setting the CLUSTER environment variable. ++ ++-------- -------- -------- ++ ++## Upgrade procedure (0.72.2 to 0.80): ++ ++ * Read "Upgrade Sequencing" in release notes: ++ ++ http://ceph.com/docs/firefly/release-notes/ ++ ++ * Upgrade packages. ++ ++ * Restart MONs. ++ ++ * Restart all OSDs. ++ ++ * Run `ceph osd crush tunables default`. ++ ++ * (Restart MDSes). ++ ++ * Consider setting the 'hashpspool' flag on your pools (new default): ++ ++ ceph osd pool set {pool} hashpspool true ++ ++ This changes the pool to use a new hashing algorithm for the distribution of ++ Placement Groups (PGs) to OSDs. This new algorithm ensures a better distribution ++ to all OSDs. Be aware that this change will temporarly put some of your PGs into ++ "misplaced" state and cause additional I/O until all PGs are moved to their new ++ location. See http://tracker.ceph.com/issues/4128 for the details about the new ++ algorithm. ++ ++ Read more about tunables in ++ ++ http://ceph.com/docs/master/rados/operations/crush-map/#tunables ++ ++ Upgrading all OSDs and setting correct tunables is necessary to avoid the errors like: ++ ++ ## rbdmap errors: ++ libceph: mon2 192.168.0.222:6789 socket error on read ++ ++ Wrong tunables may produce the following error: ++ ++ libceph: mon0 192.168.0.222:6789 socket error on read ++ libceph: mon2 192.168.0.250:6789 feature set mismatch, my 4a042a42 < server's 2004a042a42, missing 20000000000 ++ ++ ## MDS errors: ++ one or more OSDs do not support TMAP2OMAP; upgrade OSDs before starting MDS (or downgrade MDS) ++ ++ See also: ++ ++ http://ceph.com/docs/firefly/install/upgrading-ceph/ ++ ++-------- -------- -------- ++ ++ Jerasure pool(s) will bump requirements to Linux_3.15 (not yet released) for ++ kernel CephFS and RBD clients. ++ ++-------- -------- -------- ++ ++ RBD kernel driver do not support authentication so the following setting ++ in "/etc/ceph/ceph.conf" may be used to relax client auth. requirements: ++ ++ cephx cluster require signatures = true ++ cephx service require signatures = false ++ ++-------- -------- -------- ++ ++> How to mount CephFS using fuse client from "/etc/fstab"? ++ ++ Add (and modify) the following sample to "/etc/fstab": ++ ++ mount.fuse.ceph#conf=/etc/ceph/ceph.conf,id=admin /mnt/ceph fuse _netdev,noatime,allow_other 0 0 ++ ++ This is equivalent of running ++ ++ ceph-fuse /mnt/ceph --id=admin -o noatime,allow_other ++ ++ as root. ++ ++-------- -------- -------- ++ ++ To avoid known issue with kernel FS client it is recommended to use ++ 'readdir_max_entries' mount option, for example: ++ ++ mount -t ceph 1.2.3.4:/ /mnt/ceph -o readdir_max_entries=64 ++ ++-------- -------- -------- ++ ++ Beware of "mlocate" scanning of OSD file systems. To avoid problems add ++ "/var/lib/ceph" to PRUNEPATHS in the "/etc/updatedb.conf" like in the ++ following example: ++ ++ PRUNEPATHS="/tmp /var/spool /media /mnt /var/lib/ceph" ++ ++-------- -------- -------- diff --cc debian/calc-max-parallel.sh index 000000000,000000000..1cdd2bfbf new file mode 100755 --- /dev/null +++ b/debian/calc-max-parallel.sh @@@ -1,0 -1,0 +1,37 @@@ ++#!/bin/sh ++# ++# Simple tool to calculate max parallel jobs based on ++# memory of builder. ++# ++# MDCache.cc generally runs out of RAM in 4G of memory ++# with parallel=4 ++ ++if [ ""$(dpkg-architecture -qDEB_HOST_ARCH_BITS) = 32 ] ; then ++ echo "--max-parallel=1" ++ exit 0 ++fi ++ ++total_ram=$(grep MemTotal /proc/meminfo | awk '{ print $2 }') ++ ++sixtyfour_g=$((64*1024*1024)) ++fourtyheight_g=$((48*1024*1024)) ++thirtytwo_g=$((32*1024*1024)) ++sixteen_g=$((16*1024*1024)) ++eight_g=$((8*1024*1024)) ++four_g=$((4*1024*1024)) ++ ++if [ ${total_ram} -le ${four_g} ]; then ++ echo "--max-parallel=1" ++elif [ ${total_ram} -le ${eight_g} ]; then ++ echo "--max-parallel=2" ++elif [ ${total_ram} -le ${sixteen_g} ]; then ++ echo "--max-parallel=3" ++elif [ ${total_ram} -le ${thirtytwo_g} ]; then ++ echo "--max-parallel=6" ++elif [ ${total_ram} -le ${fourtyheight_g} ]; then ++ echo "--max-parallel=8" ++elif [ ${total_ram} -le ${sixtyfour_g} ]; then ++ echo "--max-parallel=12" ++else ++ echo "--max-parallel=16" ++fi diff --cc debian/ceph-base.ceph.init index 000000000,000000000..b538109d2 new file mode 120000 --- /dev/null +++ b/debian/ceph-base.ceph.init @@@ -1,0 -1,0 +1,1 @@@ ++../src/init-ceph diff --cc debian/ceph-base.dirs index 000000000,000000000..cf605ad44 new file mode 100644 --- /dev/null +++ b/debian/ceph-base.dirs @@@ -1,0 -1,0 +1,9 @@@ ++var/lib/ceph/bootstrap-mds ++var/lib/ceph/bootstrap-mgr ++var/lib/ceph/bootstrap-osd ++var/lib/ceph/bootstrap-rbd ++var/lib/ceph/bootstrap-rbd-mirror ++var/lib/ceph/bootstrap-rgw ++var/lib/ceph/crash ++var/lib/ceph/crash/posted ++var/lib/ceph/tmp diff --cc debian/ceph-base.docs index 000000000,000000000..b43bf86b5 new file mode 100644 --- /dev/null +++ b/debian/ceph-base.docs @@@ -1,0 -1,0 +1,1 @@@ ++README.md diff --cc debian/ceph-base.install index 000000000,000000000..9265be836 new file mode 100644 --- /dev/null +++ b/debian/ceph-base.install @@@ -1,0 -1,0 +1,19 @@@ ++## install from source tree ++lib/systemd/system/ceph-crash.service ++usr/bin/ceph-crash ++usr/bin/ceph-kvstore-tool ++usr/bin/ceph-run ++usr/bin/crushtool ++usr/bin/monmaptool ++usr/bin/osdmaptool ++usr/lib/*/ceph/erasure-code/* ++usr/lib/*/rados-classes/* ++usr/lib/ceph/ceph_common.sh ++usr/sbin/ceph-create-keys ++usr/share/doc/ceph/sample.ceph.conf ++usr/share/man/man8/ceph-create-keys.8 ++usr/share/man/man8/ceph-kvstore-tool.8 ++usr/share/man/man8/ceph-run.8 ++usr/share/man/man8/crushtool.8 ++usr/share/man/man8/monmaptool.8 ++usr/share/man/man8/osdmaptool.8 diff --cc debian/ceph-base.postinst index 000000000,000000000..23712a8b4 new file mode 100644 --- /dev/null +++ b/debian/ceph-base.postinst @@@ -1,0 -1,0 +1,61 @@@ ++#!/bin/sh ++# vim: set noet ts=8: ++# postinst script for ceph ++# ++# see: dh_installdeb(1) ++ ++set -e ++ ++# summary of how this script can be called: ++# ++# postinst configure ++# old-postinst abort-upgrade ++# conflictor's-postinst abort-remove in-favour ++# postinst abort-remove ++# deconfigured's-postinst abort-deconfigure in-favour [ ] ++# ++# The current action is to simply remove the mistakenly-added ++# /etc/init/ceph.conf file; this could be done in any of these cases, ++# although technically it will leave the system in a different state ++# than the original install that included that file. So instead we ++# only remove on "configure", since that's the only time we know we're ++# successful in installing a newer package than the erroneous version. ++ ++# for details, see http://www.debian.org/doc/debian-policy/ or ++# the debian-policy package ++ ++[ -f "/etc/default/ceph" ] && . /etc/default/ceph ++[ -z "$SERVER_USER" ] && SERVER_USER=ceph ++[ -z "$SERVER_GROUP" ] && SERVER_GROUP=ceph ++ ++case "$1" in ++ configure) ++ rm -f /etc/init/ceph.conf ++ for DIR in `ls -1 /var/lib/ceph` ; do ++ if ! dpkg-statoverride --list /var/lib/ceph/$DIR >/dev/null; then ++ if [ -d /run/systemd/system ] && [ $DIR = 'mon' ]; then ++ # NOTE: upgrade file permissions for mon filesystem on ++ # systemd based installs only due to automatic ++ # restarting of ceph-mon daemon ++ chown -R $SERVER_USER:$SERVER_GROUP /var/lib/ceph/$DIR ++ else ++ chown $SERVER_USER:$SERVER_GROUP /var/lib/ceph/$DIR ++ fi ++ fi ++ done ++ ;; ++ abort-upgrade|abort-remove|abort-deconfigure) ++ : ++ ;; ++ *) ++ echo "postinst called with unknown argument \`$1'" >&2 ++ exit 1 ++ ;; ++esac ++ ++# dh_installdeb will replace this with shell code automatically ++# generated by other debhelper scripts. ++ ++#DEBHELPER# ++ ++exit 0 diff --cc debian/ceph-base.postrm index 000000000,000000000..05091b223 new file mode 100644 --- /dev/null +++ b/debian/ceph-base.postrm @@@ -1,0 -1,0 +1,13 @@@ ++#!/bin/sh ++ ++set -e ++ ++if [ "${1}" = "purge" ] ; then ++ rm -rf /var/log/ceph ++fi ++ ++#DEBHELPER# ++ ++exit 0 ++ ++ diff --cc debian/ceph-common.dirs index 000000000,000000000..ff05698c2 new file mode 100644 --- /dev/null +++ b/debian/ceph-common.dirs @@@ -1,0 -1,0 +1,3 @@@ ++etc/ceph ++var/lib/ceph ++var/log/ceph diff --cc debian/ceph-common.install index 000000000,000000000..9f6d385c2 new file mode 100755 --- /dev/null +++ b/debian/ceph-common.install @@@ -1,0 -1,0 +1,44 @@@ ++#!/usr/bin/dh-exec --with=install ++usr/share/bash-completion/completions/ceph ++usr/share/bash-completion/completions/rados ++usr/share/bash-completion/completions/radosgw-admin ++usr/share/bash-completion/completions/rbd ++lib/systemd/system/ceph.target ++lib/systemd/system/rbdmap.service ++etc/default/ceph ++usr/bin/ceph ++usr/bin/ceph-authtool ++usr/bin/ceph-conf ++usr/bin/ceph-dencoder ++usr/bin/ceph-rbdnamer ++usr/bin/ceph-syn ++usr/bin/cephfs-data-scan ++usr/bin/cephfs-journal-tool ++usr/bin/cephfs-table-tool ++usr/bin/rados ++usr/bin/radosgw-admin ++usr/bin/rbd ++usr/bin/rbdmap ++usr/bin/rbd-replay* ++usr/bin/ceph-post-file ++usr/sbin/mount.ceph sbin ++usr/lib/*/ceph/compressor/* ++usr/lib/*/ceph/crypto/* [amd64] ++usr/share/man/man8/ceph-authtool.8 ++usr/share/man/man8/ceph-conf.8 ++usr/share/man/man8/ceph-dencoder.8 ++usr/share/man/man8/ceph-rbdnamer.8 ++usr/share/man/man8/ceph-syn.8 ++usr/share/man/man8/ceph-post-file.8 ++usr/share/man/man8/ceph.8 ++usr/share/man/man8/mount.ceph.8 ++usr/share/man/man8/rados.8 ++usr/share/man/man8/radosgw-admin.8 ++usr/share/man/man8/rbd.8 ++usr/share/man/man8/rbdmap.8 ++usr/share/man/man8/rbd-replay*.8 ++usr/share/ceph/known_hosts_drop.ceph.com ++usr/share/ceph/id_rsa_drop.ceph.com ++usr/share/ceph/id_rsa_drop.ceph.com.pub ++etc/ceph/rbdmap ++lib/udev/rules.d/50-rbd.rules diff --cc debian/ceph-common.lintian-overrides index 000000000,000000000..d4041ca8e new file mode 100644 --- /dev/null +++ b/debian/ceph-common.lintian-overrides @@@ -1,0 -1,0 +1,2 @@@ ++# False-positives: ++spelling-error-in-binary * tEH the diff --cc debian/ceph-common.manpages index 000000000,000000000..643fa2a41 new file mode 100644 --- /dev/null +++ b/debian/ceph-common.manpages @@@ -1,0 -1,0 +1,1 @@@ ++debian/man/ceph-crush-location.1 diff --cc debian/ceph-common.postinst index 000000000,000000000..32e58fe06 new file mode 100644 --- /dev/null +++ b/debian/ceph-common.postinst @@@ -1,0 -1,0 +1,140 @@@ ++#!/bin/sh ++# vim: set noet ts=8: ++# postinst script for ceph-common ++# ++# see: dh_installdeb(1) ++ ++set -e ++ ++# summary of how this script can be called: ++# ++# postinst configure ++# old-postinst abort-upgrade ++# conflictor's-postinst abort-remove in-favour ++# postinst abort-remove ++# deconfigured's-postinst abort-deconfigure in-favour [ ] ++# ++ ++# for details, see http://www.debian.org/doc/debian-policy/ or ++# the debian-policy package ++ ++ ++# Let the admin override these distro-specified defaults. This is NOT ++# recommended! ++[ -f "/etc/default/ceph" ] && . /etc/default/ceph ++ ++[ -z "$SERVER_HOME" ] && SERVER_HOME=/var/lib/ceph ++[ -z "$SERVER_USER" ] && SERVER_USER=ceph ++[ -z "$SERVER_NAME" ] && SERVER_NAME="Ceph storage service" ++[ -z "$SERVER_GROUP" ] && SERVER_GROUP=ceph ++[ -z "$SERVER_UID" ] && SERVER_UID=64045 # alloc by Debian base-passwd maintainer ++[ -z "$SERVER_GID" ] && SERVER_GID=$SERVER_UID ++ ++ ++# Groups that the user will be added to, if undefined, then none. ++[ -z "$SERVER_ADDGROUP" ] && SERVER_ADDGROUP= ++ ++# Custom dpkg-maintscript-helper type function to deal with ++# nested /etc/default/ceph/ceph ++finish_mv_ceph_defaults() { ++ rm -rf "/etc/default/ceph.dpkg-backup/ceph.dpkg-remove" ++ ++ [ -e "/etc/default/ceph.dpkg-backup/ceph" ] || return 0 ++ ++ echo "Preserving user changes to /etc/default/ceph (renamed from /etc/default/ceph/ceph)..." ++ if [ -f "/etc/default/ceph" ]; then ++ mv -f "/etc/default/ceph" "/etc/default/ceph.dpkg-new" ++ fi ++ mv -f "/etc/default/ceph.dpkg-backup/ceph" "/etc/default/ceph" ++} ++ ++case "$1" in ++ configure) ++ # create user to avoid running server as root ++ # 1. create group if not existing ++ if ! getent group | grep -q "^$SERVER_GROUP:" ; then ++ echo -n "Adding group $SERVER_GROUP.." ++ addgroup --quiet --system --gid $SERVER_GID \ ++ $SERVER_GROUP 2>/dev/null ||true ++ echo "..done" ++ fi ++ # 2. create user if not existing ++ if ! getent passwd | grep -q "^$SERVER_USER:"; then ++ echo -n "Adding system user $SERVER_USER.." ++ adduser --quiet \ ++ --system \ ++ --no-create-home \ ++ --disabled-password \ ++ --uid $SERVER_UID \ ++ --gid $SERVER_GID \ ++ --home $SERVER_HOME \ ++ $SERVER_USER 2>/dev/null || true ++ echo "..done" ++ fi ++ # 3. adjust passwd entry ++ echo -n "Setting system user $SERVER_USER properties.." ++ usermod -c "$SERVER_NAME" \ ++ -d $SERVER_HOME \ ++ -g $SERVER_GROUP \ ++ $SERVER_USER ++ ++ # Unlock $SERVER_USER in case it is locked from an uninstall ++ if [ -f /etc/shadow ]; then ++ usermod -U -e '' $SERVER_USER ++ else ++ usermod -U $SERVER_USER ++ fi ++ echo "..done" ++ ++ # 5. adjust file and directory permissions ++ if ! dpkg-statoverride --list $SERVER_HOME >/dev/null ++ then ++ chown $SERVER_USER:$SERVER_GROUP $SERVER_HOME ++ chmod u=rwx,g=rx,o= $SERVER_HOME ++ fi ++ if ! dpkg-statoverride --list /var/log/ceph >/dev/null ++ then ++ chown -R $SERVER_USER:$SERVER_GROUP /var/log/ceph ++ # members of group ceph can log here, but cannot remove ++ # others' files. non-members cannot read any logs. ++ chmod u=rwx,g=rwxs,o=t /var/log/ceph ++ fi ++ ++ # 6. fix /var/run/ceph ++ if [ -d /var/run/ceph ]; then ++ echo -n "Fixing /var/run/ceph ownership.." ++ chown $SERVER_USER:$SERVER_GROUP /var/run/ceph ++ echo "..done" ++ fi ++ ++ # create /run/ceph. fail softly if systemd isn't present or ++ # something. ++ [ -x $(command -v systemd-tmpfiles)"" ] && systemd-tmpfiles --create || true ++ ++ # Complete renames of /etc/default/ceph ++ if [ -n "$2" ] && ++ dpkg --compare-versions -- "$2" le-nl 10.2.1-0ubuntu1; then ++ finish_mv_ceph_defaults ++ # Preserve dpkg-backup directory if it still contains ++ # any file ++ if ! ls -1qA "/etc/default/ceph.dpkg-backup" | grep -q . ; then ++ rm -rf "/etc/default/ceph.dpkg-backup" ++ fi ++ fi ++ ;; ++ abort-upgrade|abort-remove|abort-deconfigure) ++ : ++ ;; ++ ++ *) ++ echo "postinst called with unknown argument \`$1'" >&2 ++ exit 1 ++ ;; ++esac ++ ++# dh_installdeb will replace this with shell code automatically ++# generated by other debhelper scripts. ++ ++#DEBHELPER# ++ ++exit 0 diff --cc debian/ceph-common.postrm index 000000000,000000000..e4051180d new file mode 100644 --- /dev/null +++ b/debian/ceph-common.postrm @@@ -1,0 -1,0 +1,74 @@@ ++#!/bin/sh ++# postrm script for ceph-common ++# ++# see: dh_installdeb(1) ++ ++set -e ++ ++# summary of how this script can be called: ++# * `remove' ++# * `purge' ++# * `upgrade' ++# * `failed-upgrade' ++# * `abort-install' ++# * `abort-install' ++# * `abort-upgrade' ++# * `disappear' ++# ++# for details, see http://www.debian.org/doc/debian-policy/ or ++# the debian-policy package ++ ++ ++# Custom dpkg-maintscript-helper type function to deal with ++# nested /etc/default/ceph/ceph ++abort_mv_ceph_defaults() { ++ if [ -e "/etc/default/ceph.dpkg-backup/ceph.dpkg-remove" ]; then ++ echo "Reinstalling /etc/default/ceph/ceph that was moved away" ++ mv "/etc/default/ceph.dpkg-backup" "/etc/default/ceph" ++ mv "/etc/default/ceph/ceph.dpkg-remove" "/etc/default/ceph/ceph" ++ fi ++} ++ ++case "$1" in ++ remove) ++ ;; ++ ++ purge) ++ [ -f "/etc/default/ceph" ] && . /etc/default/ceph ++ [ -z "$SERVER_USER" ] && SERVER_USER=ceph ++ ++ rm -rf /var/log/ceph ++ rm -rf /etc/ceph ++ ++ if [ -f /etc/shadow ]; then ++ usermod -L -e 1 $SERVER_USER ++ else ++ usermod -L $SERVER_USER ++ fi ++ ++ ;; ++ ++ abort-install|abort-upgrade) ++ if [ -n "$2" ] && ++ dpkg --compare-versions -- "$2" le-nl 10.2.1-0ubuntu1; then ++ abort_mv_ceph_defaults ++ fi ++ ;; ++ ++ upgrade|failed-upgrade|disappear) ++ ;; ++ ++ *) ++ echo "postrm called with unknown argument \`$1'" >&2 ++ exit 1 ++ ;; ++esac ++ ++# dh_installdeb will replace this with shell code automatically ++# generated by other debhelper scripts. ++ ++#DEBHELPER# ++ ++exit 0 ++ ++ diff --cc debian/ceph-common.preinst index 000000000,000000000..ef14f1eb1 new file mode 100644 --- /dev/null +++ b/debian/ceph-common.preinst @@@ -1,0 -1,0 +1,29 @@@ ++#!/bin/sh ++ ++set -e ++ ++# Custom dpkg-maintscript-helper type function to deal with ++# nested /etc/default/ceph/ceph ++prepare_mv_ceph_defaults() { ++ local md5sum old_md5sum ++ md5sum="$(md5sum "/etc/default/ceph/ceph" | sed -e 's/ .*//')" ++ old_md5sum="$(dpkg-query -W -f='${Conffiles}' "ceph-common" | \ ++ sed -n -e "\'^ /etc/default/ceph/ceph ' { s/ obsolete$//; s/.* //; p }")" ++ if [ "$md5sum" = "$old_md5sum" ]; then ++ mv -f "/etc/default/ceph/ceph" "/etc/default/ceph/ceph.dpkg-remove" ++ mv -f "/etc/default/ceph" "/etc/default/ceph.dpkg-backup" ++ fi ++} ++ ++case "$1" in ++ upgrade|install) ++ if [ -d /etc/default/ceph ] && [ -n "$2" ] && ++ dpkg --compare-versions -- "$2" le-nl 10.2.1-0ubuntu1; then ++ prepare_mv_ceph_defaults ++ fi ++ ;; ++esac ++ ++#DEBHELPER# ++ ++exit 0 diff --cc debian/ceph-common.rbdmap.init index 000000000,000000000..b2de0ce8b new file mode 120000 --- /dev/null +++ b/debian/ceph-common.rbdmap.init @@@ -1,0 -1,0 +1,1 @@@ ++../src/init-rbdmap diff --cc debian/ceph-fs-common.install index 000000000,000000000..a4f0bab50 new file mode 100644 --- /dev/null +++ b/debian/ceph-fs-common.install @@@ -1,0 -1,0 +1,4 @@@ ++usr/bin/cephfs ++usr/sbin/mount.ceph sbin ++usr/share/man/man8/cephfs.8 ++usr/share/man/man8/mount.ceph.8 diff --cc debian/ceph-fuse.install index 000000000,000000000..565ef25dd new file mode 100644 --- /dev/null +++ b/debian/ceph-fuse.install @@@ -1,0 -1,0 +1,5 @@@ ++lib/systemd/system/ceph-fuse* ++usr/bin/ceph-fuse ++usr/sbin/mount.fuse.ceph sbin ++usr/share/man/man8/ceph-fuse.8 ++usr/share/man/man8/mount.fuse.ceph.8 diff --cc debian/ceph-fuse.lintian-overrides index 000000000,000000000..d4041ca8e new file mode 100644 --- /dev/null +++ b/debian/ceph-fuse.lintian-overrides @@@ -1,0 -1,0 +1,2 @@@ ++# False-positives: ++spelling-error-in-binary * tEH the diff --cc debian/ceph-fuse.manpages index 000000000,000000000..e4c9c231e new file mode 100644 --- /dev/null +++ b/debian/ceph-fuse.manpages @@@ -1,0 -1,0 +1,1 @@@ ++debian/man/mount.fuse.ceph.8 diff --cc debian/ceph-grafana-dashboards.install index 000000000,000000000..6639e5695 new file mode 100644 --- /dev/null +++ b/debian/ceph-grafana-dashboards.install @@@ -1,0 -1,0 +1,1 @@@ ++etc/grafana/dashboards/ceph-dashboard/* diff --cc debian/ceph-immutable-object-cache.install index 000000000,000000000..76daf1928 new file mode 100644 --- /dev/null +++ b/debian/ceph-immutable-object-cache.install @@@ -1,0 -1,0 +1,3 @@@ ++lib/systemd/system/ceph-immutable-object-cache* ++usr/bin/ceph-immutable-object-cache ++usr/share/man/man8/ceph-immutable-object-cache.8 diff --cc debian/ceph-mds.dirs index 000000000,000000000..984526808 new file mode 100644 --- /dev/null +++ b/debian/ceph-mds.dirs @@@ -1,0 -1,0 +1,1 @@@ ++var/lib/ceph/mds diff --cc debian/ceph-mds.install index 000000000,000000000..a26d5596c new file mode 100644 --- /dev/null +++ b/debian/ceph-mds.install @@@ -1,0 -1,0 +1,3 @@@ ++lib/systemd/system/ceph-mds* ++usr/bin/ceph-mds ++usr/share/man/man8/ceph-mds.8 diff --cc debian/ceph-mds.lintian-overrides index 000000000,000000000..c88395441 new file mode 100644 --- /dev/null +++ b/debian/ceph-mds.lintian-overrides @@@ -1,0 -1,0 +1,13 @@@ ++# False-positives: ++spelling-error-in-binary * tEH the ++ ++# Ceph upstart configuration don't have equivalent init scripts ++ceph-mds: init.d-script-not-marked-as-conffile etc/init.d/ceph-mds-all ++ceph-mds: init.d-script-not-included-in-package etc/init.d/ceph-mds-all ++ceph-mds: init.d-script-not-marked-as-conffile etc/init.d/ceph-mds ++ceph-mds: init.d-script-not-included-in-package etc/init.d/ceph-mds ++ceph-mds: init.d-script-not-marked-as-conffile etc/init.d/ceph-mds-all-starter ++ceph-mds: init.d-script-not-included-in-package etc/init.d/ceph-mds-all-starter ++ceph-mds: postrm-does-not-call-updaterc.d-for-init.d-script etc/init.d/ceph-mds-all ++ceph-mds: postrm-does-not-call-updaterc.d-for-init.d-script etc/init.d/ceph-mds ++ceph-mds: postrm-does-not-call-updaterc.d-for-init.d-script etc/init.d/ceph-mds-all-starter diff --cc debian/ceph-mds.postinst index 000000000,000000000..ba91b17cd new file mode 100644 --- /dev/null +++ b/debian/ceph-mds.postinst @@@ -1,0 -1,0 +1,47 @@@ ++#!/bin/sh ++# vim: set noet ts=8: ++# postinst script for ceph-mds ++# ++# see: dh_installdeb(1) ++ ++set -e ++ ++# summary of how this script can be called: ++# ++# postinst configure ++# old-postinst abort-upgrade ++# conflictor's-postinst abort-remove in-favour ++# postinst abort-remove ++# deconfigured's-postinst abort-deconfigure in-favour [ ] ++# ++ ++# for details, see http://www.debian.org/doc/debian-policy/ or ++# the debian-policy package ++ ++[ -f "/etc/default/ceph" ] && . /etc/default/ceph ++[ -z "$SERVER_USER" ] && SERVER_USER=ceph ++[ -z "$SERVER_GROUP" ] && SERVER_GROUP=ceph ++ ++case "$1" in ++ configure) ++ if ! dpkg-statoverride --list /var/lib/ceph/mds >/dev/null; ++ then ++ chown $SERVER_USER:$SERVER_GROUP /var/lib/ceph/mds ++ fi ++ ;; ++ abort-upgrade|abort-remove|abort-deconfigure) ++ : ++ ;; ++ ++ *) ++ echo "postinst called with unknown argument \`$1'" >&2 ++ exit 1 ++ ;; ++esac ++ ++# dh_installdeb will replace this with shell code automatically ++# generated by other debhelper scripts. ++ ++#DEBHELPER# ++ ++exit 0 diff --cc debian/ceph-mgr-cephadm.install index 000000000,000000000..8dcbda165 new file mode 100644 --- /dev/null +++ b/debian/ceph-mgr-cephadm.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/share/ceph/mgr/cephadm diff --cc debian/ceph-mgr-cephadm.postinst index 000000000,000000000..18731dd07 new file mode 100644 --- /dev/null +++ b/debian/ceph-mgr-cephadm.postinst @@@ -1,0 -1,0 +1,11 @@@ ++#!/bin/sh ++ ++set -e ++ ++if [ "${1}" = "configure" ] || [ "$1" = "reconfigure" ] ; then ++ deb-systemd-invoke try-restart ceph-mgr.target ++fi ++ ++#DEBHELPER# ++ ++exit 0 diff --cc debian/ceph-mgr-dashboard.install index 000000000,000000000..8d3c8bd17 new file mode 100644 --- /dev/null +++ b/debian/ceph-mgr-dashboard.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/share/ceph/mgr/dashboard diff --cc debian/ceph-mgr-dashboard.postinst index 000000000,000000000..e681ef6b6 new file mode 100644 --- /dev/null +++ b/debian/ceph-mgr-dashboard.postinst @@@ -1,0 -1,0 +1,43 @@@ ++#!/bin/sh ++# vim: set noet ts=8: ++# postinst script for ceph-mgr-dashboard ++# ++# see: dh_installdeb(1) ++ ++set -e ++ ++# summary of how this script can be called: ++# ++# postinst configure ++# old-postinst abort-upgrade ++# conflictor's-postinst abort-remove in-favour ++# postinst abort-remove ++# deconfigured's-postinst abort-deconfigure in-favour [ ] ++# ++ ++# for details, see http://www.debian.org/doc/debian-policy/ or ++# the debian-policy package ++ ++case "$1" in ++ configure) ++ # attempt to load the plugin if the mgr is running ++ deb-systemd-invoke try-restart ceph-mgr.target ++ ;; ++ abort-upgrade|abort-remove|abort-deconfigure) ++ : ++ ;; ++ ++ *) ++ echo "postinst called with unknown argument \`$1'" >&2 ++ exit 1 ++ ;; ++esac ++ ++# dh_installdeb will replace this with shell code automatically ++# generated by other debhelper scripts. ++ ++#DEBHELPER# ++ ++exit 0 ++ ++ diff --cc debian/ceph-mgr-diskprediction-local.install index 000000000,000000000..a381e251a new file mode 100644 --- /dev/null +++ b/debian/ceph-mgr-diskprediction-local.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/share/ceph/mgr/diskprediction_local diff --cc debian/ceph-mgr-diskprediction-local.postinst index 000000000,000000000..a3293a88e new file mode 100644 --- /dev/null +++ b/debian/ceph-mgr-diskprediction-local.postinst @@@ -1,0 -1,0 +1,43 @@@ ++#!/bin/sh ++# vim: set noet ts=8: ++# postinst script for ceph-mgr-diskprediction-local ++# ++# see: dh_installdeb(1) ++ ++set -e ++ ++# summary of how this script can be called: ++# ++# postinst configure ++# old-postinst abort-upgrade ++# conflictor's-postinst abort-remove in-favour ++# postinst abort-remove ++# deconfigured's-postinst abort-deconfigure in-favour [ ] ++# ++ ++# for details, see http://www.debian.org/doc/debian-policy/ or ++# the debian-policy package ++ ++case "$1" in ++ configure) ++ # attempt to load the plugin if the mgr is running ++ deb-systemd-invoke try-restart ceph-mgr.target ++ ;; ++ abort-upgrade|abort-remove|abort-deconfigure) ++ : ++ ;; ++ ++ *) ++ echo "postinst called with unknown argument \`$1'" >&2 ++ exit 1 ++ ;; ++esac ++ ++# dh_installdeb will replace this with shell code automatically ++# generated by other debhelper scripts. ++ ++#DEBHELPER# ++ ++exit 0 ++ ++ diff --cc debian/ceph-mgr-k8sevents.install index 000000000,000000000..734da94ca new file mode 100644 --- /dev/null +++ b/debian/ceph-mgr-k8sevents.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/share/ceph/mgr/k8sevents diff --cc debian/ceph-mgr-k8sevents.postinst index 000000000,000000000..4ab578fd1 new file mode 100644 --- /dev/null +++ b/debian/ceph-mgr-k8sevents.postinst @@@ -1,0 -1,0 +1,43 @@@ ++#!/bin/sh ++# vim: set noet ts=8: ++# postinst script for ceph-mgr-k8sevents ++# ++# see: dh_installdeb(1) ++ ++set -e ++ ++# summary of how this script can be called: ++# ++# postinst configure ++# old-postinst abort-upgrade ++# conflictor's-postinst abort-remove in-favour ++# postinst abort-remove ++# deconfigured's-postinst abort-deconfigure in-favour [ ] ++# ++ ++# for details, see http://www.debian.org/doc/debian-policy/ or ++# the debian-policy package ++ ++case "$1" in ++ configure) ++ # attempt to load the plugin if the mgr is running ++ deb-systemd-invoke try-restart ceph-mgr.target ++ ;; ++ abort-upgrade|abort-remove|abort-deconfigure) ++ : ++ ;; ++ ++ *) ++ echo "postinst called with unknown argument \`$1'" >&2 ++ exit 1 ++ ;; ++esac ++ ++# dh_installdeb will replace this with shell code automatically ++# generated by other debhelper scripts. ++ ++#DEBHELPER# ++ ++exit 0 ++ ++ diff --cc debian/ceph-mgr-modules-core.install index 000000000,000000000..e99f78efb new file mode 100644 --- /dev/null +++ b/debian/ceph-mgr-modules-core.install @@@ -1,0 -1,0 +1,27 @@@ ++usr/share/ceph/mgr/alerts ++usr/share/ceph/mgr/balancer ++usr/share/ceph/mgr/crash ++usr/share/ceph/mgr/devicehealth ++usr/share/ceph/mgr/influx ++usr/share/ceph/mgr/insights ++usr/share/ceph/mgr/iostat ++usr/share/ceph/mgr/localpool ++usr/share/ceph/mgr/mirroring ++usr/share/ceph/mgr/nfs ++usr/share/ceph/mgr/orchestrator ++usr/share/ceph/mgr/osd_perf_query ++usr/share/ceph/mgr/osd_support ++usr/share/ceph/mgr/pg_autoscaler ++usr/share/ceph/mgr/progress ++usr/share/ceph/mgr/prometheus ++usr/share/ceph/mgr/rbd_support ++usr/share/ceph/mgr/restful ++usr/share/ceph/mgr/selftest ++usr/share/ceph/mgr/snap_schedule ++usr/share/ceph/mgr/stats ++usr/share/ceph/mgr/status ++usr/share/ceph/mgr/telegraf ++usr/share/ceph/mgr/telemetry ++usr/share/ceph/mgr/test_orchestrator ++usr/share/ceph/mgr/volumes ++usr/share/ceph/mgr/zabbix diff --cc debian/ceph-mgr-rook.install index 000000000,000000000..50cadb435 new file mode 100644 --- /dev/null +++ b/debian/ceph-mgr-rook.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/share/ceph/mgr/rook diff --cc debian/ceph-mgr-rook.postinst index 000000000,000000000..a3293a88e new file mode 100644 --- /dev/null +++ b/debian/ceph-mgr-rook.postinst @@@ -1,0 -1,0 +1,43 @@@ ++#!/bin/sh ++# vim: set noet ts=8: ++# postinst script for ceph-mgr-diskprediction-local ++# ++# see: dh_installdeb(1) ++ ++set -e ++ ++# summary of how this script can be called: ++# ++# postinst configure ++# old-postinst abort-upgrade ++# conflictor's-postinst abort-remove in-favour ++# postinst abort-remove ++# deconfigured's-postinst abort-deconfigure in-favour [ ] ++# ++ ++# for details, see http://www.debian.org/doc/debian-policy/ or ++# the debian-policy package ++ ++case "$1" in ++ configure) ++ # attempt to load the plugin if the mgr is running ++ deb-systemd-invoke try-restart ceph-mgr.target ++ ;; ++ abort-upgrade|abort-remove|abort-deconfigure) ++ : ++ ;; ++ ++ *) ++ echo "postinst called with unknown argument \`$1'" >&2 ++ exit 1 ++ ;; ++esac ++ ++# dh_installdeb will replace this with shell code automatically ++# generated by other debhelper scripts. ++ ++#DEBHELPER# ++ ++exit 0 ++ ++ diff --cc debian/ceph-mgr.dirs index 000000000,000000000..636b3cf4a new file mode 100644 --- /dev/null +++ b/debian/ceph-mgr.dirs @@@ -1,0 -1,0 +1,1 @@@ ++var/lib/ceph/mgr diff --cc debian/ceph-mgr.install index 000000000,000000000..fd7b68e82 new file mode 100644 --- /dev/null +++ b/debian/ceph-mgr.install @@@ -1,0 -1,0 +1,4 @@@ ++lib/systemd/system/ceph-mgr* ++usr/bin/ceph-mgr ++usr/share/ceph/mgr/mgr_module.* ++usr/share/ceph/mgr/mgr_util.* diff --cc debian/ceph-mgr.postinst index 000000000,000000000..6d38ccf09 new file mode 100644 --- /dev/null +++ b/debian/ceph-mgr.postinst @@@ -1,0 -1,0 +1,51 @@@ ++#!/bin/sh ++# vim: set noet ts=8: ++# postinst script for ceph-mgr ++# ++# see: dh_installdeb(1) ++ ++set -e ++ ++# summary of how this script can be called: ++# ++# postinst configure ++# old-postinst abort-upgrade ++# conflictor's-postinst abort-remove in-favour ++# postinst abort-remove ++# deconfigured's-postinst abort-deconfigure in-favour [ ] ++# ++ ++# for details, see http://www.debian.org/doc/debian-policy/ or ++# the debian-policy package ++ ++[ -f "/etc/default/ceph" ] && . /etc/default/ceph ++[ -z "$SERVER_USER" ] && SERVER_USER=ceph ++[ -z "$SERVER_GROUP" ] && SERVER_GROUP=ceph ++ ++case "$1" in ++ configure) ++ [ -x /sbin/start ] && start ceph-mgr-all || : ++ ++ if ! dpkg-statoverride --list /var/lib/ceph/mgr >/dev/null ++ then ++ chown $SERVER_USER:$SERVER_GROUP /var/lib/ceph/mgr ++ fi ++ ;; ++ abort-upgrade|abort-remove|abort-deconfigure) ++ : ++ ;; ++ ++ *) ++ echo "postinst called with unknown argument \`$1'" >&2 ++ exit 1 ++ ;; ++esac ++ ++# dh_installdeb will replace this with shell code automatically ++# generated by other debhelper scripts. ++ ++#DEBHELPER# ++ ++exit 0 ++ ++ diff --cc debian/ceph-mon.dirs index 000000000,000000000..e2845f602 new file mode 100644 --- /dev/null +++ b/debian/ceph-mon.dirs @@@ -1,0 -1,0 +1,1 @@@ ++var/lib/ceph/mon diff --cc debian/ceph-mon.install index 000000000,000000000..ff429f17a new file mode 100644 --- /dev/null +++ b/debian/ceph-mon.install @@@ -1,0 -1,0 +1,4 @@@ ++lib/systemd/system/ceph-mon* ++usr/bin/ceph-mon ++usr/bin/ceph-monstore-tool ++usr/share/man/man8/ceph-mon.8 diff --cc debian/ceph-mon.postinst index 000000000,000000000..454ffc141 new file mode 100644 --- /dev/null +++ b/debian/ceph-mon.postinst @@@ -1,0 -1,0 +1,46 @@@ ++#!/bin/bash ++# vim: set noet ts=8: ++# postinst script for ceph-mon ++# ++# see: dh_installdeb(1) ++ ++set -e ++ ++# summary of how this script can be called: ++# ++# postinst configure ++# old-postinst abort-upgrade ++# conflictor's-postinst abort-remove in-favour ++# postinst abort-remove ++# deconfigured's-postinst abort-deconfigure in-favour [ ] ++# ++ ++# for details, see http://www.debian.org/doc/debian-policy/ or ++# the debian-policy package ++ ++[ -f "/etc/default/ceph" ] && . /etc/default/ceph ++[ -z "$SERVER_USER" ] && SERVER_USER=ceph ++[ -z "$SERVER_GROUP" ] && SERVER_GROUP=ceph ++ ++case "$1" in ++ configure) ++ : ++ ;; ++ abort-upgrade|abort-remove|abort-deconfigure) ++ : ++ ;; ++ ++ *) ++ echo "postinst called with unknown argument \`$1'" >&2 ++ exit 1 ++ ;; ++esac ++ ++# dh_installdeb will replace this with shell code automatically ++# generated by other debhelper scripts. ++ ++#DEBHELPER# ++ ++exit 0 ++ ++ diff --cc debian/ceph-osd.dirs index 000000000,000000000..b7fc47618 new file mode 100644 --- /dev/null +++ b/debian/ceph-osd.dirs @@@ -1,0 -1,0 +1,1 @@@ ++var/lib/ceph/osd diff --cc debian/ceph-osd.install index 000000000,000000000..d9558b80d new file mode 100644 --- /dev/null +++ b/debian/ceph-osd.install @@@ -1,0 -1,0 +1,21 @@@ ++debian/udev/* lib/udev/rules.d ++etc/sudoers.d/ceph-osd-smartctl ++etc/sysctl.d/30-ceph-osd.conf ++lib/systemd/system/ceph-osd* ++lib/systemd/system/ceph-volume@.service ++usr/bin/ceph-bluestore-tool ++usr/bin/ceph-clsinfo ++usr/bin/ceph-erasure-code-tool ++usr/bin/ceph-objectstore-tool ++usr/bin/ceph-osd ++usr/bin/ceph-osdomap-tool ++usr/lib/ceph/ceph-osd-prestart.sh ++usr/lib/python*/dist-packages/ceph_volume-* ++usr/lib/python*/dist-packages/ceph_volume/* ++usr/sbin/ceph-volume ++usr/sbin/ceph-volume-systemd ++usr/share/man/man8/ceph-bluestore-tool.8 ++usr/share/man/man8/ceph-clsinfo.8 ++usr/share/man/man8/ceph-osd.8 ++usr/share/man/man8/ceph-volume-systemd.8 ++usr/share/man/man8/ceph-volume.8 diff --cc debian/ceph-prometheus-alerts.install index 000000000,000000000..13b6fc46b new file mode 100644 --- /dev/null +++ b/debian/ceph-prometheus-alerts.install @@@ -1,0 -1,0 +1,1 @@@ ++etc/prometheus/ceph/ceph_default_alerts.yml diff --cc debian/ceph-resource-agents.install index 000000000,000000000..30843f62f new file mode 100644 --- /dev/null +++ b/debian/ceph-resource-agents.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/lib/ocf/resource.d/ceph/* diff --cc debian/ceph-test.install index 000000000,000000000..978d992bc new file mode 100644 --- /dev/null +++ b/debian/ceph-test.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/share/java/libcephfs-test.jar diff --cc debian/ceph.NEWS index 000000000,000000000..ee9db2f22 new file mode 100644 --- /dev/null +++ b/debian/ceph.NEWS @@@ -1,0 -1,0 +1,180 @@@ ++ceph (10.2.5-1) unstable; urgency=medium ++ ++ ## Upgrades from Debian Jessie ++ ++ Online upgrades from Ceph versions prior to Hammer (0.94.x) are not ++ supported by upstream. As Debian Jessie has Ceph Firefly (0.80.x) an ++ online upgrade from Jessie to Stretch is not possible. You have to first ++ shutdown all Ceph daemons on all nodes, upgrade everything to the new ++ version and start all daemons again. ++ ++ Ceph daemons are not automatically restarted on upgrade to minimize ++ disruption. You have to manually restart them after the upgrade. ++ ++ -- Gaudenz Steinlin Sun, 08 Jan 2017 14:57:35 +0100 ++ ++ceph (9.2.0-1) experimental; urgency=medium ++ ++ ## systemd Enablement ++ ++ For all distributions that support systemd (Debian Jessie 8.x, ++ Ubuntu >= 16.04), Ceph daemons are now managed using upstream provided ++ systemd files instead of the legacy sysvinit scripts or distro provided ++ systemd files. For example: ++ ++ systemctl start ceph.target # start all daemons ++ systemctl status ceph-osd@12 # check status of osd.12 ++ ++ To upgrade existing deployments that use the older systemd service ++ configurations (Ubuntu >= 15.04, Debian >= Jessie), you need to switch ++ to using the new ceph-mon@ service: ++ ++ systemctl stop ceph-mon ++ systemctl disable ceph-mon ++ ++ systemctl start ceph-mon@`hostname` ++ systemctl enable ceph-mon@`hostname` ++ ++ and also enable the ceph target post upgrade: ++ ++ systemctl enable ceph.target ++ ++ The main notable distro that is *not* using systemd is Ubuntu 14.04 ++ (The next Ubuntu LTS, 16.04, will use systemd instead of upstart). ++ ++ ## Ceph daemons no longer run as root ++ ++ Ceph daemons now run as user and group 'ceph' by default. The ++ ceph user has a static UID assigned by Debian to ensure consistency ++ across servers within a Ceph deployment. ++ ++ If your systems already have a ceph user, upgrading the package will cause ++ problems. We suggest you first remove or rename the existing 'ceph' user ++ and 'ceph' group before upgrading. ++ ++ When upgrading, administrators have two options: ++ ++ 1. Add the following line to 'ceph.conf' on all hosts: ++ ++ setuser match path = /var/lib/ceph/$type/$cluster-$id ++ ++ This will make the Ceph daemons run as root (i.e., not drop ++ privileges and switch to user ceph) if the daemon's data ++ directory is still owned by root. Newly deployed daemons will ++ be created with data owned by user ceph and will run with ++ reduced privileges, but upgraded daemons will continue to run as ++ root. ++ ++ 2. Fix the data ownership during the upgrade. This is the ++ preferred option, but it is more work and can be very time ++ consuming. The process for each host is to: ++ ++ 1. Upgrade the ceph package. This creates the ceph user and group. For ++ example: ++ ++ apt-get install ceph ++ ++ NOTE: the permissions on /var/lib/ceph/mon will be set to ceph:ceph ++ as part of the package upgrade process on existing *systemd* ++ based installations; the ceph-mon systemd service will be ++ automatically restarted as part of the upgrade. All other ++ filesystem permissions on systemd based installs will ++ remain unmodified by the upgrade. ++ ++ 2. Stop the daemon(s): ++ ++ systemctl stop ceph-osd@* # debian, ubuntu >= 15.04 ++ stop ceph-all # ubuntu 14.04 ++ ++ 3. Fix the ownership: ++ ++ chown -R ceph:ceph /var/lib/ceph ++ ++ 4. Restart the daemon(s): ++ ++ start ceph-all # ubuntu 14.04 ++ systemctl start ceph.target # debian, ubuntu >= 15.04 ++ ++ Alternatively, the same process can be done with a single daemon ++ type, for example by stopping only monitors and chowning only ++ '/var/lib/ceph/osd'. ++ ++ ## KeyValueStore OSD on-disk format changes ++ ++ The on-disk format for the experimental KeyValueStore OSD backend has ++ changed. You will need to remove any OSDs using that backend before you ++ upgrade any test clusters that use it. ++ ++ ## Deprecated commands ++ ++ 'ceph scrub', 'ceph compact' and 'ceph sync force' are now DEPRECATED. ++ Users should instead use 'ceph mon scrub', 'ceph mon compact' and ++ 'ceph mon sync force'. ++ ++ ## Full pool behaviour ++ ++ When a pool quota is reached, librados operations now block indefinitely, ++ the same way they do when the cluster fills up. (Previously they would ++ return -ENOSPC). By default, a full cluster or pool will now block. If ++ your librados application can handle ENOSPC or EDQUOT errors gracefully, ++ you can get error returns instead by using the new librados ++ OPERATION_FULL_TRY flag. ++ ++ -- James Page Mon, 30 Nov 2015 09:23:09 +0000 ++ ++ceph (0.80.9-2) unstable; urgency=medium ++ ++ ## CRUSH fixes in 0.80.9 ++ ++ The 0.80.9 point release fixes several issues with CRUSH that trigger excessive ++ data migration when adjusting OSD weights. These are most obvious when a very ++ small weight change (e.g., a change from 0 to .01) triggers a large amount of ++ movement, but the same set of bugs can also lead to excessive (though less ++ noticeable) movement in other cases. ++ ++ However, because the bug may already have affected your cluster, fixing it ++ may trigger movement back to the more correct location. For this reason, you ++ must manually opt-in to the fixed behavior. ++ ++ In order to set the new tunable to correct the behavior: ++ ++ ceph osd crush set-tunable straw_calc_version 1 ++ ++ Note that this change will have no immediate effect. However, from this ++ point forward, any ‘straw’ bucket in your CRUSH map that is adjusted will get ++ non-buggy internal weights, and that transition may trigger some rebalancing. ++ ++ You can estimate how much rebalancing will eventually be necessary on your ++ cluster with: ++ ++ ceph osd getcrushmap -o /tmp/cm ++ crushtool -i /tmp/cm --num-rep 3 --test --show-mappings > /tmp/a 2>&1 ++ crushtool -i /tmp/cm --set-straw-calc-version 1 -o /tmp/cm2 ++ crushtool -i /tmp/cm2 --reweight -o /tmp/cm2 ++ crushtool -i /tmp/cm2 --num-rep 3 --test --show-mappings > /tmp/b 2>&1 ++ wc -l /tmp/a # num total mappings ++ diff -u /tmp/a /tmp/b | grep -c ^+ # num changed mappings ++ ++ Divide the total number of lines in /tmp/a with the number of lines ++ changed. We've found that most clusters are under 10%. ++ ++ You can force all of this rebalancing to happen at once with: ++ ++ ceph osd crush reweight-all ++ ++ Otherwise, it will happen at some unknown point in the future when ++ CRUSH weights are next adjusted. ++ ++ ## Mapping rbd devices with rbdmap on systemd systems ++ ++ If you have setup rbd mappings in /etc/ceph/rbdmap and corresponding mounts ++ in /etc/fstab things might break with systemd because systemd waits for the ++ rbd device to appear before the legacy rbdmap init file has a chance to run ++ and drops into emergency mode if it times out. ++ ++ This can be fixed by adding the nofail option in /etc/fstab to all rbd ++ backed mount points. With this systemd does not wait for the device and ++ proceeds with the boot process. After rbdmap mapped the device, systemd ++ detects the new device and mounts the file system. ++ ++ -- Gaudenz Steinlin Mon, 04 May 2015 22:49:48 +0200 diff --cc debian/ceph.lintian-overrides index 000000000,000000000..99b3db84b new file mode 100644 --- /dev/null +++ b/debian/ceph.lintian-overrides @@@ -1,0 -1,0 +1,1 @@@ ++empty-binary-package diff --cc debian/cephadm.install index 000000000,000000000..f30ed9c5f new file mode 100644 --- /dev/null +++ b/debian/cephadm.install @@@ -1,0 -1,0 +1,2 @@@ ++usr/sbin/cephadm ++usr/share/man/man8/cephadm.8 diff --cc debian/cephadm.postinst index 000000000,000000000..aea89a7af new file mode 100644 --- /dev/null +++ b/debian/cephadm.postinst @@@ -1,0 -1,0 +1,46 @@@ ++#!/bin/sh ++ ++set -e ++ ++CEPHADM_HOME=/var/lib/cephadm ++ ++if [ "${1}" = "configure" ] || [ "${1}" = "reconfigure" ] ; then ++ if ! getent group cephadm > /dev/null 2>&1 ; then ++ addgroup --quiet --system cephadm ${ADDGROUP_PARAM} ++ fi ++ ++ if ! getent passwd cephadm ; then ++ echo -n "Adding system user cephadm..." ++ adduser --system \ ++ --home /var/lib/cephadm \ ++ --no-create-home \ ++ --quiet \ ++ --disabled-password \ ++ --gecos 'cephadm user for mgr/cephadm' \ ++ --shell /bin/bash \ ++ --group cephadm \ ++ cephadm 2>/dev/null || true ++ echo "done" ++ fi ++ ++ if [ ! -d ${CEPHADM_HOME} ] ; then ++ mkdir -p ${CEPHADM_HOME} ++ fi ++ chown cephadm:cephadm ${CEPHADM_HOME} ++ chmod 0755 ${CEPHADM_HOME} ++ ++ if ! [ -d ${CEPHADM_HOME}/.ssh ] ; then ++ mkdir ${CEPHADM_HOME}/.ssh ++ chown --reference ${CEPHADM_HOME} ${CEPHADM_HOME}/.ssh ++ chmod 0700 ${CEPHADM_HOME}/.ssh ++ fi ++ if ! [ -e ${CEPHADM_HOME}/.ssh/authorized_keys ] ; then ++ touch ${CEPHADM_HOME}/.ssh/authorized_keys ++ chown --reference ${CEPHADM_HOME} ${CEPHADM_HOME}/.ssh/authorized_keys ++ chmod 0600 ${CEPHADM_HOME}/.ssh/authorized_keys ++ fi ++fi ++ ++#DEBHELPER# ++ ++exit 0 diff --cc debian/cephfs-mirror.install index 000000000,000000000..19d2e483d new file mode 100644 --- /dev/null +++ b/debian/cephfs-mirror.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/bin/cephfs-mirror diff --cc debian/cephfs-shell.install index 000000000,000000000..4713a81b1 new file mode 100644 --- /dev/null +++ b/debian/cephfs-shell.install @@@ -1,0 -1,0 +1,2 @@@ ++usr/bin/cephfs-shell ++usr/lib/python3*/dist-packages/cephfs_shell-*.egg-info diff --cc debian/cephfs-top.install index 000000000,000000000..930396b0c new file mode 100644 --- /dev/null +++ b/debian/cephfs-top.install @@@ -1,0 -1,0 +1,2 @@@ ++usr/bin/cephfs-top ++usr/lib/python3*/dist-packages/cephfs_top-*.egg-info diff --cc debian/changelog index 000000000,000000000..b998c71fd new file mode 100644 --- /dev/null +++ b/debian/changelog @@@ -1,0 -1,0 +1,1621 @@@ ++ceph (16.2.6+ds-11) unstable; urgency=medium ++ ++ * Revert libcephfs2.symbols "fix". ++ ++ -- Thomas Goirand Tue, 28 Dec 2021 08:45:18 +0100 ++ ++ceph (16.2.6+ds-10) unstable; urgency=medium ++ ++ * Fix libcephfs2.symbols. ++ * Build-depends only on python3-dev, not python3-all-dev (Closes: #1002688). ++ ++ -- Thomas Goirand Mon, 27 Dec 2021 15:48:02 +0100 ++ ++ceph (16.2.6+ds-9) unstable; urgency=medium ++ ++ * Fix ceph-mgr-modules-core,ceph-mgr: both ship /usr/share/ceph/mgr/* ++ (Closes: #998826). ++ ++ -- Thomas Goirand Mon, 27 Dec 2021 10:16:27 +0100 ++ ++ceph (16.2.6+ds-8) unstable; urgency=medium ++ ++ * Uploading to unstable. ++ ++ -- Thomas Goirand Fri, 24 Dec 2021 23:46:33 +0100 ++ ++ceph (16.2.6+ds-7) experimental; urgency=medium ++ ++ [ Adrian Bunk ] ++ * Use the system libfmt ++ * Use the system liburing ++ * Optimize for space on 32bit architectures ++ * Don't let cmake append CFLAGS/CXXFLAGS is -O/-g settings different from ++ what we set. ++ ++ -- Thomas Goirand Thu, 23 Dec 2021 15:53:49 +0100 ++ ++ceph (16.2.6+ds-6) experimental; urgency=medium ++ ++ * Use -DWITH_BOOST_CONTEXT=ON in s390x mips64el and riscv64. ++ * Fix cmake-test-for-16-bytes-atomic-support-on-mips-also.patch so that it ++ works also for 32 bits mips. ++ ++ -- Thomas Goirand Thu, 09 Dec 2021 13:54:42 +0100 ++ ++ceph (16.2.6+ds-5) experimental; urgency=medium ++ ++ * Add cmake-test-for-16-bytes-atomic-support-on-mips-also.patch which fixes ++ FTBFS on mips64el. ++ * Add only-yied-under-armv7-and-above.patch which fixes FTBFS on armel. ++ ++ -- Thomas Goirand Sat, 20 Nov 2021 15:00:51 +0100 ++ ++ceph (16.2.6+ds-4) experimental; urgency=medium ++ ++ * Add libgoogle-perftools-dev build-depends on all available arch. ++ * Remove a symbol in debian/libcephfs2.symbols that is missing on ppc64el. ++ * Removed useless libsqlite3-mod-ceph.symbols. ++ ++ -- Thomas Goirand Mon, 08 Nov 2021 20:44:04 +0100 ++ ++ceph (16.2.6+ds-3) experimental; urgency=medium ++ ++ * Do not maintain debian/librados2.symbols. ++ ++ -- Thomas Goirand Mon, 08 Nov 2021 08:36:08 +0100 ++ ++ceph (16.2.6+ds-2) experimental; urgency=medium ++ ++ * Build-depends on valgrind for all avialable arch. ++ * Build-depends on libboost-context-dev and libboost-coroutine-dev on ++ s390x, mips64el and riscv64. ++ ++ -- Thomas Goirand Sun, 07 Nov 2021 15:14:08 +0100 ++ ++ceph (16.2.6+ds-1) experimental; urgency=medium ++ ++ * New upstream release. ++ * Exclude debian folder from upstream orig tarball. ++ * Commit some of the upstream packaging to be closer to their packaging. ++ * Refreshed patch: ++ - disable-crypto.patch ++ - riscv64-link-pthread.patch ++ - compile-ppc.c-on-all-powerpc-machines.patch ++ * Remove patch (now useless / NA): ++ - 32bit-avoid-overloading.patch ++ - 32bit-avoid-size_t.patch ++ - make-ceph-python-3.9-aware.patch ++ - patches/another-cmakelists-fix.patch ++ - cmake_add_1.74_to_known_versions.patch ++ - cmake_define_BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT_for_Boost...sers.patch ++ - allow-bgp-to-host.patch ++ * Add patch taken from Ubuntu: ++ - enable-strsignal.patch ++ - 32bit-fixes.patch ++ - disable-log-slow-requests.patch ++ - bug1914584.patch ++ - bug1917414.patch ++ * Removed patch applied upstream: ++ - bluefs-use-uint64_t-for-len.patch ++ - debian/patches/mds-purgequeue-use_uint64_t.patch ++ * Rebased patch: ++ - add-option-to-disable-ceph-dencoder.patch ++ * d/rules: import stuff from the Ubuntu packaging. ++ * Reviewed build-dependency list. ++ * Switch to debhelper-compat 11. ++ * Use dh_installsystemd, not dh_systemd_enable which is deprecated. ++ * Reviewed (and rewrote a lot of) debian/copyright. ++ * Do not override dh_systemd_enable and dh_systemd_start. ++ ++ -- Thomas Goirand Tue, 02 Nov 2021 14:48:40 +0100 ++ ++ceph (14.2.21-1.1) unstable; urgency=medium ++ ++ * Non-maintainer upload. ++ * Compile ppc.c on all powerpc machines. Fixes 32 bit powerpc build ++ (Closes: #993642). ++ ++ -- Mattias Ellert Thu, 26 Aug 2021 10:36:49 +0200 ++ ++ceph (14.2.21-1) unstable; urgency=high ++ ++ * New upstream release, resolving these: ++ - CVE-2021-3509: Cross Site Scripting via token Cookie (Closes: #988888). ++ - CVE-2021-3524: injection of HTTP headers via a CORS ExposeHeader tag in ++ the Ceph Storage RadosGW (Closes: #988889). ++ - CVE-2021-3531: RadosGW denial of service (crash) (Closes: #988890). ++ ++ -- Thomas Goirand Thu, 27 May 2021 12:04:21 +0200 ++ ++ceph (14.2.20-2) unstable; urgency=medium ++ ++ * Add allow-bgp-to-host.patch. ++ ++ -- Thomas Goirand Wed, 21 Apr 2021 10:02:07 +0200 ++ ++ceph (14.2.20-1) unstable; urgency=medium ++ ++ * New upstream point release (Closes: #986173): ++ - Fixes CVE-2021-20288: Unauthorized global_id reuse in cephx ++ (Closes: #986974) ++ * Remove "rm -rf /etc/ceph" in ceph-base.postinst (Closes: #987192). ++ ++ -- Thomas Goirand Tue, 20 Apr 2021 13:00:13 +0200 ++ ++ceph (14.2.18-1) unstable; urgency=medium ++ ++ * New upstream point release. ++ * Refreshed 32bit-avoid-size_t.patch. ++ * Rebased bluefs-use-uint64_t-for-len.patch. ++ * Refreshed 32bit-avoid-size_t.patch. ++ * Refreshed riscv64-link-pthread.patch. ++ * Rebased ++ cmake_define_BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT_for_Boost.Asio_users.patch ++ * Refreshed another-cmakelists-fix.patch. ++ * Removed allow-binding-on-lo.patch applied upstream. ++ ++ -- Thomas Goirand Wed, 24 Mar 2021 12:49:20 +0100 ++ ++ceph (14.2.16-2) unstable; urgency=medium ++ ++ * Add fix-ceph-osd-systemd-target.patch. ++ ++ -- Thomas Goirand Thu, 28 Jan 2021 16:45:23 +0100 ++ ++ceph (14.2.16-1) unstable; urgency=medium ++ ++ * Add allow-binding-on-lo.patch. ++ * New upstream release. ++ ++ -- Thomas Goirand Fri, 15 Jan 2021 12:26:14 +0100 ++ ++ceph (14.2.15-4) unstable; urgency=medium ++ ++ * Add upstream 3 patches for libboost 1.74 (Closes: #977243). ++ ++ -- Thomas Goirand Sun, 13 Dec 2020 16:33:57 +0100 ++ ++ceph (14.2.15-3) unstable; urgency=medium ++ ++ [ Adrian Bunk ] ++ * [197afaf] Merge branch 'debian/unstable' into 'debian/unstable' ++ Portability fixes ++ See merge request ceph-team/ceph!6 ++ ++ -- Thomas Goirand Thu, 03 Dec 2020 21:03:06 +0100 ++ ++ceph (14.2.15-2) unstable; urgency=medium ++ ++ * Do not build with clang, instead, set --max-parallel=1, as it seems it ++ worked for Ubuntu. If this doesn't work, we'll disable the non-64 bits ++ arch completely. ++ ++ -- Thomas Goirand Mon, 30 Nov 2020 21:10:12 +0100 ++ ++ceph (14.2.15-1) unstable; urgency=medium ++ ++ * New upstream release (Closes: #956750): ++ - Fix FTBFS with GCC-10 (Closes: #957079). ++ - Fix CVE-2020-10753 (Closes: #963760). ++ - Fix CVE-2020-25660 (Closes: #975275). ++ * Refreshed patches: ++ - 32bit-avoid-size_t.patch ++ - add-option-to-disable-ceph-dencoder.patch ++ - bluefs-use-uint64_t-for-len.patch ++ - disable-crypto.patch ++ - mds-purgequeue-use_uint64_t.patch ++ * Raw wrap-and-sort -bastk. ++ * Added myself as uploader. ++ * Added librdkafka-dev as build-depends. ++ * Fixed debian/libcephfs-dev.install. ++ * debian/calc-max-parallel.sh: allow for more values of --max-parallel so ++ that ceph builds faster on more powerful machines. ++ * Add a patch to make Ceph aware of Python 3.9: ++ - make-ceph-python-3.9-aware.patch ++ * Add a debian/source/options to ignore CRLF to CR changes. ++ * Use --home in ceph-common.postinst when creating the Ceph system user. ++ * Updated debian/libcephfs2.symbols (added 3 new symbols). ++ * Package: ceph-resource-agents, switch Priority: to optional. ++ * Add debian/source.lintian-overrides to allow .js which shipped by upstream ++ in both compiled and source version. ++ * Removed now useless dpkg-maintscript-helper rm_conffile: they have been ++ around for more than one release. ++ * debian/ceph-osd.postinst: remove as it's doing nothing. ++ * Fix debian/lib{rbd1,rados2}.symbols (3 missing symbols). ++ ++ -- Thomas Goirand Fri, 27 Nov 2020 23:58:00 +0100 ++ ++ceph (14.2.9-1) unstable; urgency=high ++ ++ * [dc4e7cf] Update upstream source from tag 'upstream/14.2.9' ++ Update to upstream version '14.2.9' ++ with Debian dir 544321a5823a0e5b826198888c79cb3ed4dd9b2e ++ Closing #956142 / CVE-2020-1760 ++ ++ -- Bernd Zeimetz Fri, 24 Apr 2020 22:43:18 +0200 ++ ++ceph (14.2.8-2) unstable; urgency=medium ++ ++ * [eed9184] Fix 32bit issues in src/mds/PurgeQueue.cc ++ mips64el (as reported in the bug report) built fine. ++ s390x is a buildd issue, gets stuck sometimes for unknown (and not ++ reproducible) reasons. ++ Other build issues are fixed hopefully. ++ Thanks to Ivo De Decker (Closes: #953749) ++ ++ -- Bernd Zeimetz Mon, 23 Mar 2020 00:14:25 +0100 ++ ++ceph (14.2.8-1) unstable; urgency=medium ++ ++ * [e14a030] Update upstream source from tag 'upstream/14.2.8' ++ Update to upstream version '14.2.8' ++ with Debian dir 6c28e7789e84694b28409f0aceb9bfe6f2acdade ++ Closes: #953364 ++ * [6bc660e] Refreshing patches ++ * [9e935e3] Fix FTBFS on riscv64. ++ Thanks to Aurelien Jarno (Closes: #953003) ++ * [4287e84] fix lintian override ++ ++ -- Bernd Zeimetz Sun, 08 Mar 2020 22:31:55 +0100 ++ ++ceph (14.2.7-1) unstable; urgency=medium ++ ++ * [a68d12f] Update upstream source from tag 'upstream/14.2.7' ++ Update to upstream version '14.2.7' ++ with Debian dir 1125b03b88e8da85cf70f7cc540c1c30fa95d456 ++ This also contains a fix for ++ [CVE-2020-1700]: Fixed a flaw in RGW beast frontend that ++ could lead to denial of service from an unauthenticated client. ++ CVE-2020-1699 was patched since 14.2.6-3. ++ * [1474595] Removing patches applied upstream ++ ++ -- Bernd Zeimetz Sat, 01 Feb 2020 00:47:27 +0100 ++ ++ceph (14.2.6-6) unstable; urgency=medium ++ ++ * [c18d632] Remove broken patch (Option::TYPE_SIZE as uint64_t). ++ This patch actually results in a segfault while parsing options. ++ Revert it and then see what it was actually needed for on 32bit. ++ Thanks to Martin Mlynář (Closes: #949743) ++ * [b5c7be8] Update patch with a non-segfaulting version. ++ Took me some time to figure out that in option.cc size_t is not what you ++ expect, but a struct instead, just with the same name. ++ So to make clang happy we'll use static_cast now, although ++ this will for sure show various other issues on 32bit as not all ++ possible config values will fit into 32bit numbers. ++ Fixing this will need a lot of upstream work unfortunately. ++ ++ -- Bernd Zeimetz Sun, 26 Jan 2020 15:39:29 +0100 ++ ++ceph (14.2.6-5) unstable; urgency=medium ++ ++ * [966df1a] Removing cython from Build-deps. ++ Thanks to Sandro Tosi (Closes: #936282) ++ * [38fdd89] clang ist not available on sh4 ++ * [3c97474] Replace findstring by filter where needed. ++ Thanks jrtc27 for the hint. ++ * [c694d0d] Pass -DHAVE_NEON=0 to cmake on armel. ++ Instead of "fixing" CMakeCache.txt. ++ * [825a942] Revert "Don't build ceph on mipsel." ++ This reverts commit 424ea9b82f956daa8fa9c0539d0752ccfdc7caf6. ++ Thanks to peter green (Closes: #949528) ++ * [79aef26] Remove merge fail ++ ++ -- Bernd Zeimetz Tue, 21 Jan 2020 21:21:17 +0100 ++ ++ceph (14.2.6-4) unstable; urgency=high ++ ++ * Really uploading to unstable now. ++ ++ -- Bernd Zeimetz Sat, 18 Jan 2020 19:58:32 +0100 ++ ++ceph (14.2.6-3) experimental; urgency=high ++ ++ * Uploading to unstable, including changes to make ceph ++ build on mipsel again (Closes: #948722). ++ * [1bac6f0] mgr/dashboard: fix improper URL checking. ++ This change disables up-level references beyond the HTTP base directory. ++ [CVE-2020-1699] ++ Upstream commit 0443e40c11280ba3b7efcba61522afa70c4f8158 ++ Thanks to Salvatore Bonaccorso (Closes: #949206) ++ * [720ce76] Updating changelog (from experimental) ++ ++ -- Bernd Zeimetz Sat, 18 Jan 2020 19:11:22 +0100 ++ ++ceph (14.2.6-2) experimental; urgency=medium ++ ++ * [fc4df2f] d/rules: make sure mips doesn't match on mipsel/mips64el ++ * [3d9ed86] Add patch to disable dencoder build if needed. ++ * [ce0c9bb] Don't build ceph-dencoder on mipsel. ++ Its a debugging tool and does not build on mipsel due to g++/clang++ ++ running out of memory. ++ Replacing it by a shellscript that prints an error message. ++ * [0d83e22] Configure gbp for experimental ++ ++ -- Bernd Zeimetz Thu, 16 Jan 2020 23:59:37 +0100 ++ ++ceph (14.2.6-1) unstable; urgency=medium ++ ++ [ James Page ] ++ * [2e50d5b] Fix misnamed package Recommends brbd1 -> librbd1 ++ * [11df8ed] Add missing debhelper misc:Depends for python3-ceph ++ * [08c3c8b] Add missing Depends on python3-{distutils,routes} to ceph-mgr-dashboard package ++ ++ [ Bernd Zeimetz ] ++ * [a87f434] Update upstream source from tag 'upstream/14.2.6' ++ Update to upstream version '14.2.6' ++ with Debian dir f37aa9f99ec09cc88d8e5e468c1f642fa7f77ef1 ++ * [e91626b] Revert "Fix ceph-mgr - indefinite queue growth hangs" ++ This reverts commit 010db9a30458a6417ff667c3c11a3870edb8ee0c. ++ Patches were applied upstream for 14.2.6 ++ ++ -- Bernd Zeimetz Sun, 12 Jan 2020 23:13:27 +0100 ++ ++ceph (14.2.5-3) unstable; urgency=medium ++ ++ * Uploading to unstable ++ ++ * [010db9a] Fix ceph-mgr - indefinite queue growth hangs. ++ Applying the backport for the fix ++ https://github.com/ceph/ceph/pull/32466 ++ Thanks to Milan Kupcevic (Closes: #947969) ++ * [b01de37] Merge branch 'debian/unstable' into debian/experimental ++ * [c8f35e5] Add breaks/replaces for ceph-common - ceph mds. ++ * [ee905cb] Revert "Configure gbp for experimental" ++ This reverts commit 3bcd5ac5f416b902a868036c243d7f19752c82f8. ++ * [6303513] Revert "CI: build in experimental" ++ This reverts commit d481122833e611c69c28e2b381e1cc1c8f689385. ++ * [f1a9482] Snapshot changelog ++ * [6e955c8] Removing automatic Ubuntu header ++ * [b90d95a] Mark patch as forwarded ++ ++ -- Bernd Zeimetz Tue, 07 Jan 2020 20:50:28 +0100 ++ ++ceph (14.2.5-2) experimental; urgency=medium ++ ++ * [8c74414] lower --max-parallel for >=16GB ++ g++ loves to eat ram ++ * [b15dcdd] Build-dep. on python3-dev instead python3-all-dev. ++ Thanks to Graham Inggs (Closes: #948021) ++ * [d481122] CI: build in experimental ++ * [4303a75] 32bit: fix more size_t vs uint64_t issues. ++ * [c98ea07] Install bash-completion in /usr again. ++ This change went missing somewhere during the import of the ++ changes done in Ubuntu between 12.2.11 and 14.2.4. ++ Thanks to Andreas Beckmann (Closes: #948165) ++ * [c7d90b9] Move manpages to ceph-common again. ++ This also went missing during the import. ++ * [3e5a680] Use a better way to check if we are on 32bit. ++ * [c03cd06] rm d/p/boost-py37-compat.patch. ++ Upstream renamed assert.h to ceph_assert.h, so this patch should not be ++ necessary anymore. ++ ++ -- Bernd Zeimetz Sun, 05 Jan 2020 00:04:23 +0100 ++ ++ceph (14.2.5-1) experimental; urgency=medium ++ ++ [ Bernd Zeimetz ] ++ * [3bcd5ac] Configure gbp for experimental ++ * [bd0b051] New upstream version 14.2.5 ++ * [46cbe61] Merge upstream changes for 14.2.5 ++ * [4dfd819] Refreshing patches ++ * [da26f25] Fix copy&paste errors in build-deps. ++ * [7ff43a2] Mark build-deps needed for make check. ++ And remove the need to install them. ++ * [5ef8ac3] Remove left over patch file ++ * [91ab5b9] */lib_tp.so files are not built, don't install them. ++ * [44591e4] Don't try to install files we don't build ++ * [db0994e] librbd1.symbols: add new symbols. ++ * [d53724e] Add install/postinstall files for ceph-mgr-k8sevents ++ * [acada37] Add lintian override for .chm file. ++ Source and build info is shipped. ++ * [bbb0bd6] copy the radosgw init file in override_dh_installinit. ++ * [a5958d5] Avoid duplicate files. ++ etc/bash_completion.d/ceph was accidentally shipped in ceph-base again. ++ * [fbc33a3] Add missing > in Dependency. ++ ++ -- Bernd Zeimetz Thu, 02 Jan 2020 10:52:50 +0100 ++ ++ceph (14.2.4-9) unstable; urgency=medium ++ ++ * [8c74414] lower --max-parallel for >=16GB ++ g++ loves to eat ram ++ * [b15dcdd] Build-dep. on python3-dev instead python3-all-dev. ++ Thanks to Graham Inggs (Closes: #948021) ++ * [c98ea07] Install bash-completion in /usr again. ++ This change went missing somewhere during the import of the ++ changes done in Ubuntu between 12.2.11 and 14.2.4. ++ Thanks to Andreas Beckmann (Closes: #948165) ++ * [c7d90b9] Move manpages to ceph-common again. ++ This also went missing during the import. ++ ++ -- Bernd Zeimetz Sun, 05 Jan 2020 00:22:21 +0100 ++ ++ceph (14.2.4-8) unstable; urgency=medium ++ ++ * [e187e6a] Use WITH_CCACHE from cmake to build with ccache. ++ * [8cbe25e] Hack CMakeCache.txt to disable HAVE_ARM_NEON on armel. ++ after trying to patch the various places where HAVE_ARM_NEON is used ++ the easiest way to get rid of it on armel seems to be to patch the cmake ++ cache file. ++ * [424ea9b] Don't build ceph on mipsel. ++ No compiler is able to build the code without running into oom-issues. ++ ++ -- Bernd Zeimetz Wed, 01 Jan 2020 19:29:48 +0100 ++ ++ceph (14.2.4-7) unstable; urgency=medium ++ ++ * [9b97753] Make sure we use ccache if needed. ++ * [3dbd1ac] d/rules: Remove the armel fpu options. ++ Hopefully properly patched now. ++ * [da253e4] m68k, sh4: build with clang to avoid gcc OOM. ++ ++ -- Bernd Zeimetz Tue, 31 Dec 2019 00:13:23 +0100 ++ ++ceph (14.2.4-6) unstable; urgency=medium ++ ++ * [b1c9b5d] Try to reduce memory usage even further if needed. ++ gcc loves to eat too much memory on armhf mipsel armel. ++ * [d695778] Remove softfp patch in favour of build flags. ++ This hopefully avoids the need to update and debug the patch. ++ * [6eddb32] Build with clang(++) on armhf mipsel armel. ++ Reports seem to suggest that clang does not need as much memory as gcc. ++ * [b9420ba] Fix unsigned/size_t issue for sh4 & m86k. ++ * [0027181] Updating changelog ++ * [6502f60] Fix another 32bit size_t/uint64_t issue. ++ In src/common/options.cc line 192. ++ * [4a0b044] Fix another 32bit size_t/uint64_t issue. ++ This time: powerpc. ++ ++ -- Bernd Zeimetz Sun, 29 Dec 2019 17:38:10 +0100 ++ ++ceph (14.2.4-5) unstable; urgency=medium ++ ++ [ Bernd Zeimetz ] ++ * [453eaa4] Avoid using make -j 32 on powerpc. ++ A lot of CPU do not always help. ++ ++ [ Milan Kupcevic ] ++ * [c6ec924] cherry pick critical bluestore data corruption fix ++ (Closes: #947457) ++ ++ [ Bernd Zeimetz ] ++ * [e88fc21] Set -DWITH_BOOST_CONTEXT=OFF where necessary. ++ [!s390x !mips64el !ia64 !m68k !ppc64 !riscv64 !sh4 !sparc64 !x32] ++ ++ -- Bernd Zeimetz Sat, 28 Dec 2019 15:54:51 +0100 ++ ++ceph (14.2.4-4) unstable; urgency=medium ++ ++ * [b70efb1] Create missing directories for arch:all build. ++ * [3e4530f] try to save even more memory on armhf. ++ Don't build debug flags at all. ++ * [b478ee5] Avoid overloading on mipsel. ++ Add mipsel to debian/patches/32bit-avoid-overloading.patch ++ * [85eb6e9] Also build jerasure with softfp on armel. ++ ++ -- Bernd Zeimetz Thu, 26 Dec 2019 16:03:51 +0100 ++ ++ceph (14.2.4-3) unstable; urgency=medium ++ ++ [ Bernd Zeimetz ] ++ * [f3f47f5] CI: disable extra-long running tests. ++ ++ [ Steve Langasek ] ++ * [9794fc4] Drop uninstallable and unneeded server binaries on i386. ++ (Closes: #947156) ++ ++ [ Bernd Zeimetz ] ++ * [6c2993f] Merge tag 'debian/14.2.4-0ubuntu3' into debian/unstable ++ * [0c5b41f] Use a tracker.d.o list instead of a closed one. (Closes: #760538) ++ * [d95db97] Try to build with --max-parallel=1 on slow arches. ++ We run into out-of-memory errors again. ++ * [e8d9e63] Use -mfloat-abi=softfp on armel for NEON instructions. ++ And again, that patch went missing somewhere. ++ Taken from ++ https://salsa.debian.org/ceph-team/ceph/commit/fa7d0d84f736d0b8450572f3192a43ff7b3252c4 ++ ++ -- Bernd Zeimetz Tue, 24 Dec 2019 13:03:45 +0100 ++ ++ceph (14.2.4-2) unstable; urgency=medium ++ ++ [ Thomas Goirand ] ++ * [4b2327d] Add a python3-ceph metapackage. ++ ++ [ Bernd Zeimetz ] ++ * [dbc7d2f] Add lintian override for empty python3-ceph package. ++ * [5381390] Remove -en from description. ++ We actually want to have a description in the changes file... ++ * [4a57f31] Make python3-ceph dependencies binNMU safe ++ ++ -- Bernd Zeimetz Thu, 28 Nov 2019 09:43:37 +0100 ++ ++ceph (14.2.4-1) unstable; urgency=medium ++ ++ * Uploading 14.2.4 to Debian. ++ (Closes: #936282, #943961, #940854, #942733) ++ * Adding missing sources (two.js, bootstrap 3.3.4) ++ * ceph-mon.postinst missed the interpreter ++ * Add missing dependency on python3 ++ * ignore lintian errors about minified js with shipped sources ++ * Radowgw uses a systemd template, override lintian. ++ * libcephfs-jni: rpath to java libraries needed. ++ Add lintian override. ++ * Remove .pc folder from debian folder. ++ * Adding myself to Uploaders ++ * Merging the work done in Ubuntu. ++ ++ [ Dariusz Gadomski ] ++ * d/p/issue37490.patch: Cherry pick fix to optimize LVM queries in ++ ceph-volume, resolving performance issues in systems under heavy load ++ or with large numbers of disks (LP: #1850754). ++ ++ [ James Page ] ++ * d/p/issue40114.patch: Cherry pick endian fixes to resolve issues ++ using Ceph on big-endian architectures such as s390x (LP: #1851290). ++ * New upstream release (LP: #1850901): ++ - d/p/more-py3-compat.patch,ceph-volume-wait-for-lvs.patch, ++ ceph-volume-wait-for-lvs.patch: Drop, included upstream. ++ - d/p/bluefs-use-uint64_t-for-len.patch: Cherry pick fix to resolve ++ FTBFS on 32 bit architectures. ++ * d/rules: Disable SPDK support as this generates a build which ++ has a minimum CPU baseline of 'corei7' on x86_64 which is not ++ compatible with older CPU's (LP: #1842020). ++ * d/p/issue40781.patch: Cherry pick fix for py3 compatibility in ceph- ++ crash. ++ ++ [ Eric Desrochers ] ++ * Ensure that daemons are not automatically restarted during package ++ upgrades (LP: #1840347): ++ - d/rules: Use "--no-restart-after-upgrade" and "--no-stop-on-upgrade" ++ instead of "--no-restart-on-upgrade". ++ - d/rules: Drop exclusion for ceph-[osd,mon,mds] for restarts. ++ ++ [ Jesse Williamson ] ++ * d/p/civetweb-755-1.8-somaxconn-configurable*.patch: Backport changes ++ to civetweb to allow tuning of SOMAXCONN in Ceph RADOS Gateway ++ deployments (LP: #1838109). ++ ++ [ James Page ] ++ * d/p/ceph-volume-wait-for-lvs.patch: Cherry pick inflight fix to ++ ensure that required wal and db devices are present before ++ activating OSD's (LP: #1828617). ++ ++ [ Steve Beattie ] ++ * SECURITY UPDATE: RADOS gateway remote denial of service ++ - d/p/CVE-2019-10222.patch: rgw: asio: check the remote endpoint ++ before processing requests. ++ - CVE-2019-10222 ++ - Closes: #936015 ++ ++ [ James Page ] ++ * New upstream release. ++ * d/p/fix-py3-encoding-fsid.patch: Drop, no longer required. ++ * d/p/pybind-auto-encode-decode-cstr.patch: Drop, reverted upstream. ++ * d/p/fix-py3-encoding-fsid.patch: Cherry pick correct fix to resolve ++ FSID encoding issues under Python 3 (LP: #1833079). ++ * d/p/pybind-auto-encode-decode-cstr.patch: Cherry pick fix to ensure ++ that encoding/decoding of strings is correctly performed under ++ Python 3 (LP: #1833079). ++ ++ * New upstream release. ++ * d/p/misc-32-bit-fixes.patch: Drop, included upstream. ++ * d/p/py37-compat.patch: Drop, included upstream. ++ * d/p/collections.abc-compat.patch: Drop, included in release. ++ * d/p/*: Refresh. ++ * d/*: Re-sync packaging with upstream for Nautilus release. ++ * d/control,ceph-test.*,rules: Disable build of test binaries, drop ++ ceph-test binary package (reduce build size). ++ * d/control,rules: Use system boost libraries (reduce build time). ++ * d/control: Add dependency on smartmontools, suggest use of nvme-cli ++ for ceph-osd package. ++ * d/p/32bit-*.patch: Fix misc 32 bit related issues which cause ++ compilation failures on armhf and i386 architectures. ++ * d/control: Add Breaks/Replaces on ceph-common for ceph-argparse to ++ deal with move of Python module. ++ ++ * New upstream release (LP: #1810766). ++ * d/p/*: Refresh. ++ ++ * d/p/more-py3-compat.patch: Add more py3 fixes. ++ ++ * d/p/more-py3-compat.patch: Misc Python 3 fixes in ceph-create-keys. ++ ++ * d/tests/python-ceph: Fix python3 test support resolving ++ autopkgtest failure. ++ ++ * New upstream point release. ++ * d/p/*: Refresh. ++ * d/control,python-*.install,rules: Drop Python 2 support. ++ * d/tests: Update for Python 2 removal. ++ * d/p/misc-32-bit-fixes.patch: Update type of rgw_max_attr_name_len, ++ resolving SIGABRT in radosgw (LP: #1805145). ++ * d/p/boost-py37-compat.patch: Fix compilation issue with boost ++ imports conflicting with ceph's assert.h header. ++ * d/p/collections.abc-compat.patch: Selective cherry-pick of upstream ++ fix for future compatibility with Python 3.8, avoiding deprecation ++ warnings under Python 3.7. ++ ++ * d/ceph-mds.install: Install missing systemd configuration ++ (LP: #1789927). ++ ++ * Re-instate 32bit architectures. ++ - d/control: Switch back to linux-any ++ - d/p/misc-32-bit-fixes.patch: Misc fixes for compilation ++ failures under 32 bit architectures. ++ - d/rules: Disable SPDK integration under i386. ++ * Repack upstream tarball, excluding non-DFSG sources (LP: #1750848): ++ - d/copyright: Purge upstream tarball of minified js files, which ++ are neither shipped in binaries or required for package build. ++ - d/watch: Add dversionmangle for +dfsg\d version suffix. ++ * d/control,rules: Drop requirement for gcc-7 for arm64. ++ * d/ceph-osd.udev: Add udev rules for sample LVM layout for OSD's, ++ ensuring that LV's have ceph:ceph ownership (LP: #1767087). ++ ++ * d/copyright,source.lintian-overrides: Exclude jsonchecker component ++ of rapidjson avoiding license-problem-json-evil non-free issue. ++ * New upstream point release. ++ * d/control: Remove obsolete X{S}-* fields. ++ ++ * New upstream release. ++ * Sync with changes in upstream packaging: ++ - d/*.install,rules: Use generated systemd unit files for install ++ - d/ceph-test.install: Drop binaries removed upstream. ++ * d/p/*: Refresh and drop as needed. ++ * d/*.symbols: Refresh for new release. ++ * d/rules,calc-max-parallel.sh: Automatically calculate the maximum ++ number of parallel compilation units based on total memory. ++ * d/control: Drop support for 32 bit architectures. ++ * d/control: Update Vcs-* fields for Ubuntu. ++ * d/control: Drop min python version field. ++ ++ -- Bernd Zeimetz Mon, 18 Nov 2019 14:18:10 +0100 ++ ++ceph (12.2.11+dfsg1-2.1) unstable; urgency=medium ++ ++ * Non-maintainer upload. ++ * [3194010] Install ceph-volume@.service into ceph-osd. ++ (Closes: #924061) ++ ++ -- Bernd Zeimetz Fri, 05 Apr 2019 15:12:52 +0200 ++ ++ceph (12.2.11+dfsg1-2) unstable; urgency=medium ++ ++ * [27a321] Fix builds on 32bit architectures ++ * [346bfa] Fix linking radosgw without BEAST frontend ++ ++ -- Gaudenz Steinlin Tue, 19 Feb 2019 08:50:12 +0100 ++ ++ceph (12.2.11+dfsg1-1) unstable; urgency=medium ++ ++ * [8b6f70] Build depend on cmake >= 3.13.2 ++ * [98ed84] New upstream version 12.2.11+dfsg1 ++ - Fixes CVE-2018-14662, CVE-2018-16889, CVE-2018-16846 ++ (Closes: #921948, #918969, #921947) ++ * [4d5c86] Mark all LTTng tracepoints symbols as optional ++ * [b92a2f] Build depend on debhelper >= 11.5.4~ ++ * [5781cc] Add Breaks/Replaces ceph-base (<< 12.2.10+dfsg1-1~) to ceph-common ++ (Closes: #919898) ++ * [658bd3] Fixup Breaks/Replaces for files moved between binary packages ++ * [c24137] Install systemd units for Ceph MGR service ++ (Closes: #920176, #919871) ++ * [091e14] Remove no longer needed dpkg-maintscript-helper calls in radosgw ++ * [567dde] Temp changelog commit ++ ++ -- Gaudenz Steinlin Tue, 12 Feb 2019 10:55:02 +0100 ++ ++ceph (12.2.10+dfsg1-1) unstable; urgency=medium ++ ++ * [22146e] ceph-base: create directory for bootstrap-rbd key ++ * [8c0362] Move ceph bash completion to ceph-common ++ * [b9e790] Make ceph binary package Suggests binNMU safe ++ * [fc83f1] Install ceph-fuse systemd service file ++ * [e70c29] Enable LTTng ++ * [234e9b] New upstream version 12.2.10+dfsg1 ++ ++ -- Gaudenz Steinlin Sat, 29 Dec 2018 22:08:52 +0100 ++ ++ceph (12.2.8+dfsg1-5) unstable; urgency=medium ++ ++ * [66e03b] Fix linking on archs which require libatomic ++ * [5236f3] Fix Python 3 autopkgtest ++ ++ -- Gaudenz Steinlin Fri, 30 Nov 2018 16:49:02 +0100 ++ ++ceph (12.2.8+dfsg1-4) unstable; urgency=medium ++ ++ * [97dfb6] Fix detection of armel for NEON instructions (Closes: #913599) ++ ++ -- Gaudenz Steinlin Thu, 22 Nov 2018 22:33:21 +0100 ++ ++ceph (12.2.8+dfsg1-3) unstable; urgency=medium ++ ++ * [168bb9] Build depend on pythonX-dev instead of pythonX-all-dev ++ (Closes: #912905) ++ * [38d140] Patch to check for atomic support during build (Closes: #913601) ++ * [9cc0a5] Disable libboost-context on unsupported archs (Closes: #913600) ++ * [238143] Fix building with -g1 on 32 bit architectures ++ * [3b48d5] Use -mfloat-abi=softfp on armel for NEON instructions ++ (Closes: #913599) ++ ++ -- Gaudenz Steinlin Thu, 22 Nov 2018 09:38:09 +0100 ++ ++ceph (12.2.8+dfsg1-2) unstable; urgency=medium ++ ++ * [5c4b36] Add architecture specific symbols for librados2 ++ * [38bc1b] Build depend on libatomic1 on armel, m68k, mips, mipsel, powerpc, ++ powerpcspe and sh4 ++ ++ -- Gaudenz Steinlin Wed, 31 Oct 2018 23:38:05 +0100 ++ ++ceph (12.2.8+dfsg1-1) unstable; urgency=medium ++ ++ [ James Page ] ++ * [9c55f6] Ensure that systemd targets are enabled and started ++ * [17ca38] Support optional runtime loading of openssl in radosgw ++ * [8927f6] Fix build on i386 ++ * [774281] Ensure all ceph modules are included in the binary package. ++ * [00ca38] Cherry pick upstream fix to resolve FTBFS on armhf ++ * [5d118c] Add ceph-volume tools to ceph-osd package ++ ++ [ Gaudenz Steinlin ] ++ * [ba768b] New upstream version 12.2.8+dfsg1 ++ (Closes: #852999, #864535, #893149) ++ * [96eba0] Exclude jsonchecker from upstream source ++ * [7dd73b] Exclude Windows help file from orig tarball ++ * [9d1740] Move ceph initscript and systemd target to ceph-base ++ * [8ae049] Drop obsolete patches (either upstreamed or because of switch to ++ cmake) ++ * [cfd095] Create directory for Ceph Manager bootstrap keys ++ * [858194] Shell scripts moved out of architecture specific directory ++ * [f3f387] Merge ceph-fs-common package into ceph-common ++ * [1789fe] Move radosgw-admin to ceph-common ++ * [6f51fc] Add compressor plugins to ceph-common ++ * [5bd0d1] Add crypto plugins to ceph-common on amd64 ++ * [7724f7] New binary package ceph-mgr ++ * [804be6] Remove librgw_file* from ceph-test. These are unit tests for rgw. ++ * [fef87a] Upstream changed the build system to cmake ++ * [134e34] Build Python 3 versions of Python modules (Closes: #883148) ++ * [52a969] Package RADOS gateway Python bindings (python-rgw) ++ * [a48700] Add rados-objclass-dev binary package ++ * [30306f] Update dependencies for new upstream release ++ * [4d07af] libcephfs1 -> libcephfs2 soname bumped upstream ++ * [c4022d] Remove ceph-disk-udev no longer shipped upstream ++ * [9aad82] Remove sample.fetch_config no longer shipped upstream ++ * [fc163d] Update copyright for new upstream release ++ * [21c408] Add /usr/bin/radosgw-es to radosgw package ++ * [f63b2a] ceph-osd: sysctl config to increase the maximum number of AIO ++ requests ++ * [5f1f30] Remove static libraries from -dev packages (removed upstream) ++ * [1db168] Install ceph-detect-init into /usr/bin instead of /usr/sbin ++ * [1fb625] Move ceph-*-tool from ceph-test into daemon packages ++ * [6a5628] Remove obsolete X-Python-Version ++ * [c6fc4d] Update to Debian Policy version 4.2.1 ++ * [5821f2] Set multiarch triplet in debian/rules ++ * [9bdce0] Remove override of dh_auto_install ++ * [b71c87] Add libceph-common to librados2 and librados-dev pkgs ++ * [c746ce] Override JSON license lintian warning (false positive, code ++ removed) ++ * [17d65c] Use dh_missing instead of dh_install --list-missing ++ * [cba40a] Remove obsolete ceph-create-keys@.service from ceph-base ++ * [252d62] Update watch file for https and repacking ++ * [ef84cf] Install ceph SysV init script with dh_install ++ * [0c2c84] Add missing source for jquery.flot.js (actually ++ jquery.colorhelpers.js) ++ * [0f1e2e] Add missing sources for JQuery in civetweb ++ * [8010cc] Add missing sources from AdminLTE ++ * [7c425a] Add lintian overrides for source-is-missing false positives ++ * [75f7d2] Update symbols files ++ * [aa7295] Patch to fix build failures with Boost 1.67 ++ * [872887] Build with Debian packaged Boost 1.67 instead of bundled Boost 1.66 ++ * [abf215] Use google-perftools on all supported architectures ++ * [44dd74] Add missing sources for the mgr dashboard plugin ++ * [39f9d6] Depend on ceph-common for pythonX-cephfs (Closes: #896400) ++ * [7a10f0] Improve autopkgtests ++ * [7515ca] Add Python dependency for ceph-fuse ++ * [d91a92] Make the ceph binary package a pure metapackage ++ * [df1dc8] Add Lintian overrides for systemd targets ++ * [bc7cd4] Install upstream rbdmap systemd service file ++ * [dd44ea] Remove RUNPATH from JNI libraries ++ * [7e9bce] Add dependency on junit4 and libcephfs-java for ceph-test ++ * [dfbe7c] Remove unnecessary ceph-base postrm script (Closes: #867465) ++ * [bad29d] Fix permissions on /var/run/ceph in SysV init script ++ (Closes: #869142) ++ * [6edc7a] Mark libraries as Multi-Arch compatible (Closes: #822740) ++ ++ [ Thomas Goirand ] ++ * [46be6f] Change VCS links to point to Salsa ++ ++ [ Shengjing Zhu ] ++ * [bfcf95] Don't treat rados-classes and ceph/compressor as shared libraries ++ * [0ef4f9] Add missing interpreter in ceph-{osd,mon}.postinst ++ (Closes: #862684, #862685) ++ * [f75bfc] Change section of libcephfs-jni from libs to java ++ * [f4b5d4] Add patch to fix various spelling errors ++ * [f60d21] Patch to remove link to ceph.com for dashboard favicon ++ * [116028] Backport test build fix from upstream ++ * [b83166] Change architecture of ceph-fuse to linux-any (from amd64) ++ ++ -- Gaudenz Steinlin Sun, 28 Oct 2018 23:43:10 +0100 ++ ++ceph (10.2.5-7.2) unstable; urgency=medium ++ ++ * Non-maintainer upload. ++ * Build with -g1 instead of -g on 32bit architectures to fix ++ FTBFS due to the 2GB/3GB address space limits. ++ ++ -- Adrian Bunk Wed, 07 Jun 2017 11:39:39 +0300 ++ ++ceph (10.2.5-7.1) unstable; urgency=medium ++ ++ * Non-maintainer upload. ++ * ceph-mon: Add Breaks+Replaces: ceph-common (<< 10) for taking over ++ /usr/bin/ceph-rest-api. (Closes: #864161) ++ ++ -- Andreas Beckmann Tue, 06 Jun 2017 09:08:30 +0200 ++ ++ceph (10.2.5-7) unstable; urgency=medium ++ ++ * [a12798] Add fix-init-system-detection.patch. ++ This replaces the static init system detection by more appropriate ++ runtime detection which also works if a Debian system is running with ++ sysvinit. (Closes: #862075) ++ ++ -- Gaudenz Steinlin Fri, 12 May 2017 12:12:00 +0200 ++ ++ceph (10.2.5-6) unstable; urgency=medium ++ ++ * [e44a30] Disable running dh_auto_install with parallel jobs ++ (Closes: #850906) ++ * [b7e926] Link with libatomic and --as-needed on all archs (Closes: #850831) ++ ++ -- Gaudenz Steinlin Wed, 11 Jan 2017 12:02:24 +0100 ++ ++ceph (10.2.5-5) unstable; urgency=medium ++ ++ * [f4675d] Set _FILE_OFFSET_BITS=64 via DEB_CPPFLAGS_MAINT_APPEND ++ * [f60392] Install systemd targets for ceph services (Closes: #850509) ++ * [d3baba] Link with -latomic on mips/mipsel ++ ++ -- Gaudenz Steinlin Tue, 10 Jan 2017 09:04:48 +0100 ++ ++ceph (10.2.5-4) unstable; urgency=medium ++ ++ * [88034c] Build with ggc-min-expand=5 on mips/el (Closes: #849657) ++ * [c31e79] Add patch to build rocksdb with -latomic on mips/el ++ * [182dd8] NEWS entry about upgrades from Debian Jessie ++ ++ -- Gaudenz Steinlin Sun, 08 Jan 2017 21:34:21 +0100 ++ ++ceph (10.2.5-3) unstable; urgency=medium ++ ++ * [eeff8d] Use -mfloat-abi=softfp on armel for NEON plugin (Closes: #849660) ++ ++ -- Gaudenz Steinlin Thu, 05 Jan 2017 09:18:41 +0100 ++ ++ceph (10.2.5-2) unstable; urgency=medium ++ ++ * [3859ca] Only list missing files instead of failing (Closes: #849031) ++ * [47aef7] Remove chrony from recommends (provides time-daemon) ++ (Closes: #827673) ++ * [3e96e6] Upstream fix for CVE-2016-9579 (short CORS request) ++ (Closes: #849048) ++ ++ -- Gaudenz Steinlin Sat, 24 Dec 2016 13:14:28 +0100 ++ ++ceph (10.2.5-1) unstable; urgency=medium ++ ++ [ James Page ] ++ * [754935] Imported Upstream version 9.2.0 ++ - [df85c3] Resync relevant packaging changes with upstream. ++ - [be5f82] Refresh patches. ++ - [d1f3fe] Add python-setuptools to BD's for ceph-detect-init. ++ - [b2f926] Add lsb-release to BD's to ensure that python modules are ++ installed to correct locations. ++ - [e4d702] Add python-sphinx to BD's to ensure man pages get generated ++ and installed. ++ - [3ead6e] Correct install location for ceph-monstore-update tool. ++ - [269754] [177b7a] Update symbols for new release. ++ * [4c45629] Update NEWS file for infernalis changes. ++ * [940491e] Limit number of parallel builds to 2 to reduce memory footprint ++ on builders. ++ * [a2bed4] New upstream version 10.2.5 ++ * [cbfb6b] Sync upstream changes around rbdmap install and conf files. ++ * [5c52b2] Drop patches include upstream, refresh remaining patches ++ * [8f9820] Resync further packaging changes from upstream. ++ * [27d010] Re-add bz2-dev BD. ++ * [e94aa2] Add python-dev to BD's. ++ * [e201c1] d/p/pybind-flags.patch: Ensure that cython *FLAGS are correctly ++ set. ++ * [14cd12] d/p/fix-systemd-escaping.patch: Ensure that leading '/' is stripped ++ from block device paths when escaping for use in systemd unit ++ names. ++ * [33b3aa] Add pull request for systemd fixes ++ * [d781a2] d/ceph-mds.postinst: Fix syntax error. ++ * [ce55ec] Ensure that python flags are correct set for cython rbd build. ++ * [f9e35b] Switch rbd python binding to cython ++ * [8ccae0] Drop ceph_volume_client until its actually in the codebase. ++ * [0a11cc] Install to relative, not absolute /etc/ceph. ++ * [e2415a] Drop ceph-bluefs-tool from ceph package. ++ * [b16966] d/ceph-mds.dirs: Actually create /var/lib/ceph/mds prior to ++ changing permissions (LP: #1544647). ++ * [0c1201] d/ceph.init: Restore link to init-ceph, resolving un-install ++ failures due to missing init script (LP: #1546112). ++ ++ [ Gaudenz Steinlin ] ++ * [e3cb86] Remove no longer needed check for dh-autoreconf>=6 ++ * [9157b3] Install ceph-brag tool into ceph-common ++ * [74e9f3] Install ceph-client-debug into ceph-test ++ * [476449] Use jh_installlib to install Java libraries ++ * [643f6e] Don't remove configure script on dh_clean ++ * [4bb203] Remove *.la files to binary packages ++ * [b76c6a] Add build dependency on libboost-iostreams-dev ++ * [b0506f] Add build dependency on libldap2-dev ++ * [526ce1] Refresh patches for upstream version 10.2.2 ++ * [cf539b] Remove patches applied upstream in 10.2.2 ++ ++ [ James Page ] ++ * [646b48] Add librgw2 binary packages. ++ * [ae3cda] Drop virtualenv from BD's. ++ * [7ebd7c] Re-enable rocksdb build for bluestore support ++ * [e393e5] Add rbd-mirror package ++ * [00d06d] Add patch to set g++ flags correctly for rocksdb ++ * [3b029a] Enable gperftools on arm64 architecture. ++ * [e88620] Add ceph-bluefs-tool to install. ++ * [4f40a1] Add s390x to list of rocksdb flags ++ * [858334] d/p/skip-setup.py-makefiles.patch,rules: Avoid use of virtualenv to ++ install ceph-disk and ceph-detect-init python modules. ++ * [40c3b7] Update watch file to scan for gz files. ++ * [49b716] Install librgw_file* as part of ceph-test package. ++ ++ [ Gaudenz Steinlin ] ++ * [2e156d] d/rules: Install upstart and systemd configurations for rbd-mirror. ++ ++ [ James Page ] ++ * [ca0b07] d/copyright: Ensure that jerasure and gf-complete are not stripped ++ from the upstream release tarball. ++ * [eee861] d/p/disable-openssl-linking.patch: Disable build time linking with ++ OpenSSL due to licensing incompatibilities. ++ * [07d7a6] d/*.symbols: Add new symbols for RC. ++ * [2416f1] Fix multiarch paths for librgw ++ * [2da01d] d/rules: Ensure that dh_systemd_start does not insert maintainer ++ script snippets for ceph-mon and ceph-create-keys - service restart ++ should be handled outside of the packaging as it is under upstart ++ and for all other systemd unit files installed (LP: #1563330). ++ * [76ec3b] d/ceph-common.postinst: Silence output of usermod call ++ (LP: #1569249). ++ * [63d60f] d/rules,ceph-common.install: Ensure that /etc/default/ceph is a ++ file and not a directory (LP: #1587516). ++ * [a866ca] d/control: Bumped Standards-Version to 3.9.8, no changes. ++ * [e0811e] d/ceph.install: Drop install of 60-ceph-partuuid-workaround.rules ++ as no longer part of upstream codebase. ++ * [25954f] * d/*: Split ceph-osd and ceph-mon into separate binary packages ++ and add new ceph-base binary package inline with upstream packaging ++ changes (LP: #1596063). ++ * [f1287b] Add missing misc depends ++ * [afeb18] d/rules,control: Drop -dbg packages and let Ubuntu builds take care ++ of ddeb generation instead. ++ ++ [ Gaudenz Steinlin ] ++ * [e133b2] Install rbdmap manpage into ceph-common ++ * [b5ed64] Install radosgw-token command into radosgw package ++ * [0a27e1] Adapt installation of Python files to latest Jewel release ++ * [ef2544] Drop rocksdb-flags patch applied upstream ++ * [07aef4] Add patch osd-limit-omap-data-in-push-op ++ * [32f14d] Refresh patches ++ ++ [ James Page ] ++ * [f4e95c] Fix install location for mount.ceph ++ * [6a9efc] Update install location for mount.ceph.fuse ++ * [7624f0] d/control: Add Pre-Depends on ceph-common to ceph-osd to ensure ++ that ceph user and group are created prior to unpacking of udev ++ rules (LP: #1631328). ++ ++ [ Frode Nordahl ] ++ * [022ee3] Add rgw_rados-creation_time patch ++ ++ [ Gaudenz Steinlin ] ++ * [05225f] Remove old ceph logrotate configuration ++ ++ [ James Page ] ++ * [cfa82f] Refresh patches ++ ++ [ Gaudenz Steinlin ] ++ * [fdec5d] Remove upstart support ++ * [5966f0] Use new RSA key for ceph-post-file ++ * [3748b6] Only install ChangeLog as upstream changelog ++ * [aa1393] Install bash-completions to /usr ++ * [ab0a88] Dependency on lsb-base for initscripts ++ * [4d78b0] Disable radosgw SysV init script on systemd ++ * [ff4c87] Don't install python bytecode ++ * [3cbf5e] Add missing dependencies on python (ceph-osd, ceph-mon) ++ * [8c70df] Update symbols files (librados2 and librbd1) ++ * [e4f0c5] Add ${shlibs:Depends} on Python C extensions ++ * [936838] Allow setting the number of parallel jobs ++ * [e5aa0f] Remove Laszlo and add myself to uploaders ++ ++ -- Gaudenz Steinlin Sat, 17 Dec 2016 22:40:22 +0100 ++ ++ceph (0.94.5-1) experimental; urgency=medium ++ ++ * [2d330d6] New upstream release: ++ - [1e93090] Drop patch for CVE-2015-5245, included upstream. ++ - [20adc7d] Refresh all other patches. ++ * [9255e5d] Ensure any erasure coding test libraries and dangling symlinks ++ are not included in the ceph package. ++ ++ -- James Page Mon, 09 Nov 2015 12:09:51 +0000 ++ ++ceph (0.94.3-1) experimental; urgency=medium ++ ++ * [580fef] Imported Upstream version 0.94.3 (Closes: #777814, #795178) ++ * [536935] Add upstream patch to fix CVE-2015-5245 (Closes: #798567) ++ ++ -- Gaudenz Steinlin Fri, 18 Sep 2015 16:55:23 +0200 ++ ++ceph (0.94.2-2) experimental; urgency=medium ++ ++ * Revert "Drop virtualenv BD, disable unit tests." ++ * Restore patches for test enablement. ++ * Display test-suite log output in the event of failures. ++ ++ -- James Page Mon, 20 Jul 2015 13:37:06 +0100 ++ ++ceph (0.94.2-1) experimental; urgency=medium ++ ++ * Resync with Ubuntu, introducing Ceph Hammer stable release: ++ - d/*.symbols: Update inline with upstream additions, use regex ++ for ceph version symbol. ++ - d/lib-systemd/system/ceph-create-keys.service: Automatically create ++ admin and bootstrap keys after ceph mon startup. ++ - d/p/vivid-does-systemd.patch: Ensure that disks prepared on vivid ++ or later use systemd for init. ++ - d/lib-systemd/system/*.service: Align nofile limits and restart config ++ with equivalent upstart configurations. ++ - d/p/fix-cycles-arch.patch: Skip initialization of cycles_per_sec ++ if rtdsc (or equivalent) is not supported. ++ - d/ceph{-common}.install,control: Move ceph_argparse.py down into ++ ceph-common package to fixup ceph cli usage/autopkgtest failure. ++ - d/control,ceph-common.install,librbd1.install: Move rbdnamer and ++ associated udev rules into ceph-common package. ++ - d/control,python-*: Split out rbd, rados and cephfs bindings into ++ separate python packages, move some bits into ceph/ceph-common. ++ - d/control: Move python-flask dependency to ceph package, only required ++ for REST API. ++ - d/control: Use google-perftools on arm64. ++ - d/control: Re-order Recommends to prefer ntp over chrony for Ubuntu. ++ - d/p/ceph-osd-prestart-path.patch: Fixup path for ceph-osd upstart ++ configuration pre-start script. ++ - d/p/fix-argparse-defaults.patch: Workaround behavioural change in ++ argparse set_defaults in python 2.7.9 ++ * New upstream point release: ++ - d/p/*: Refresh. ++ * d/p/use_system_jerasure.patch,d/control: Drop use of libjerasure ++ as the patch is intrusive and expensive to maintain; will revisit if ++ adopted upstream. ++ ++ -- James Page Tue, 16 Jun 2015 11:31:05 +0100 ++ ++ceph (0.87-2) experimental; urgency=low ++ ++ * Team upload. ++ ++ [ Gaudenz Steinlin ] ++ * README.Debian: added clarification about setting the hashpspool flag. ++ (Closes: #769596). ++ ++ [ James Page ] ++ * Added new "modules.patch" to mark new erasure coding libraries as ++ modules, wildcard install. ++ ++ [ Dmitry Smirnov ] ++ * Recommends: added "ntp" to list of time-daemon alternatives ++ (Closes: #767511). ++ * Introduced native systemd services (except "rbdmap"), (Closes: #769593). ++ * ceph-test: install forgotten files. ++ * Run post-build tests: ++ + updated "virtualenv-never-download.patch" to pass ++ "--system-site-packages" to virtualenv to prevent downloads. ++ + added new patches to disable network-dependent and failing tests. ++ * Patchworks: ++ - bug-9341.patch ++ + bug-10036.patch (to show OSD affinity in "ceph osd tree"). ++ Thanks, Mykola Golub. ++ + bug-10059.patch ++ + 0latest-giant.patch (Last-Update: 2014-11-15). ++ + sleep-recover.patch ++ + tests-disable.patch (to disable tests that need cluster). ++ + tests-disable-ceph-disk.patch ++ + use_system_gtest.patch (commented) ++ as first attempt to build with system "libgtest-dev". ++ + use_system_jerasure.patch ++ * Build-Depends: ++ + libjerasure-dev (>= 2.0.0-2~) ++ + virtualenv ++ + valgrind [amd64 armhf i386 powerpc] ++ * rules: pass "--without-lttng" to explicitly disable "lttng" to avoid ++ auto-enable if found. ++ * rules: disabled bundled RocksDB: ++ RocksDB suppose to improve performance of keyvaluestore OSDs but the ++ latter slow down to nearly unusable state when filled over 1 TiB even with ++ RocksDB. Moreover KV backend is experimental and super dangerous -- I lost ++ cluster due to OSD poisoning caused by KV OSD which was plugged only ++ during limited time. LevelDB is good enough, for now I see no reason to ++ use RocksDB especially considering that it is not packaged separately. ++ * Removed myself from Uploaders. ++ ++ -- Dmitry Smirnov Wed, 01 Apr 2015 11:47:38 +1100 ++ ++ceph (0.87-1) experimental; urgency=medium ++ ++ * New major upstream release [October 2014]. ++ + new "libradosstriper*" binary packages. ++ * Patchworks (removed old patches, refreshed remaining ones). ++ + "bug-9814.patch" to prevent OSD crash. Thanks, Haomai Wang. ++ * Install systemd sleep handler. ++ * Exclude erasure-code plugins from `dh_makeshlibs` processing to avoid ++ useless calls to `ldconfig` in maintainer scripts. ++ * Build-Depends: ++ + libbabeltrace-dev ++ + libbabeltrace-ctf-dev ++ + libbz2-dev ++ + libudev-dev ++ + zlib1g-dev ++ * Build with "--with-babeltrace". ++ * Build and statically link bundled RocksDB. ++ ++ -- Dmitry Smirnov Thu, 30 Oct 2014 12:43:49 +1100 ++ ++ceph (0.80.9-2) unstable; urgency=medium ++ ++ * [70fc1d] Add NEWS entry about CRUSH issues fixed in 0.80.9 ++ * [f41bb6] Add NEWS entry about rbd backed filesystems and systemd ++ ++ -- Gaudenz Steinlin Tue, 05 May 2015 21:29:15 +0200 ++ ++ceph (0.80.9-1) unstable; urgency=medium ++ ++ * [4b4e] Imported Upstream version 0.80.9 ++ * [7102] Remove patches firefly-latest and p2139 applied upstream ++ * [5869] Add myself to uploaders ++ ++ -- Gaudenz Steinlin Mon, 04 May 2015 08:49:37 +0200 ++ ++ceph (0.80.7-2) unstable; urgency=medium ++ ++ * Team upload. ++ * Build-Depends: +libjerasure-dev (>= 2.0.0-2~) ++ * New patch to use system "jerasure" library instead of its bundled copy. ++ * Removed myself from Uploaders. ++ ++ -- Dmitry Smirnov Thu, 11 Dec 2014 12:55:38 +1100 ++ ++ceph (0.80.7-1) unstable; urgency=medium ++ ++ * New upstream release [October 2014]. ++ * Minor update to long description of "rbd-fuse" (Closes: #765462). ++ ++ -- Dmitry Smirnov Thu, 16 Oct 2014 04:36:23 +1100 ++ ++ceph (0.80.6-1) unstable; urgency=medium ++ ++ * New upstream release [October 2014]. ++ * Standards-Version: 3.9.6. ++ ++ -- Dmitry Smirnov Thu, 02 Oct 2014 23:07:04 +1000 ++ ++ceph (0.80.5-2) unstable; urgency=low ++ ++ * Patchworks: ++ + new patch for Ceph#9341 to dramatically (e.g seconds instead of ++ hours) reduce rejoin (i.e. MDS restart) time (fuse clients). ++ + new "p2139.patch". ++ + new patch with fixes from Firefly HEAD; ++ includes patch to fix FTBFS on alpha (Closes: #756892). ++ updated "librbd1.symbols"; ++ * Build-Depends: mark "yasm" as [amd64] (Closes: #760383). ++ * Recommends: + "time-daemon | chrony". ++ ++ -- Dmitry Smirnov Tue, 16 Sep 2014 03:54:15 +1000 ++ ++ceph (0.80.5-1) unstable; urgency=medium ++ ++ * New upstream stable release: ++ - d/p/firefly-post-release.patch: Dropped, no longer required. ++ - d/lib{rados2,cephfs1}.symbols: Update with new symbols. ++ ++ -- James Page Wed, 30 Jul 2014 10:15:40 +0100 ++ ++ceph (0.80.4-1) unstable; urgency=medium ++ ++ * New upstream release [July 2014]. ++ * New patches: ++ + rbdmap1-mount.patch ++ + rbdmap2-hooks.patch ++ + rbdmap3-lazyumount.patch ++ + bug-8821.patch ++ * radosgw: removed unused lintian overrides. ++ ++ -- Dmitry Smirnov Fri, 18 Jul 2014 02:33:39 +1000 ++ ++ceph (0.80.1-2) unstable; urgency=low ++ ++ * Megapatch from "firefly" branch with post-0.80.1 fixes. ++ * Patches for upstream bugs 8342, 8624 and some cherry-picks. ++ * New "bash-completion.patch" with Bash completion improvements. ++ * New patch to fix FTBFS on 'hppa' (Closes: #748571). ++ * "sample.ceph.conf.patch": minor update. ++ ++ -- Dmitry Smirnov Sat, 05 Jul 2014 20:29:44 +1000 ++ ++ceph (0.80.1-1) unstable; urgency=low ++ ++ * New upstream release [May 2014]. ++ * Dropped all backported patches. ++ * New "sleep-recover" and "client-sleep[1,2,3]" patches to fix ++ fuse-client hang after resume from suspend [#8291]; thanks, Zheng Yan. ++ * New "gcj_search_path.patch" to find "jni.h" with gcj-jdk v4.9.0. ++ ++ -- Dmitry Smirnov Wed, 14 May 2014 09:24:15 +1000 ++ ++ceph (0.80-1) unstable; urgency=low ++ ++ * New upstream release [May 2014]. ++ + upload to unstable. ++ * Updated "README.Debian". ++ * Updated "debian/copyright"; Thanks, László Böszörményi. ++ * Added backported patches: ++ [8113, 8175, 8282, 8291, bp0001, sample.ceph.conf]. ++ * "gbp.conf": don't merge to experimental. ++ * lintian-overrides: spelling-error-in-binary * tEH the. ++ ++ -- Dmitry Smirnov Wed, 07 May 2014 16:43:07 +1000 ++ ++ceph (0.80~rc1-1) experimental; urgency=low ++ ++ * New upstream pre-release. ++ * Minor re-factoring of udev rules installation. ++ * ceph-common: added ceph-crush-location.1 man page. ++ * ceph-test-dbg: fixed Depends. ++ ++ -- Dmitry Smirnov Thu, 24 Apr 2014 02:52:12 +1000 ++ ++ceph (0.79-3) experimental; urgency=low ++ ++ * New "arch.patch" to detect build architecture using dpkg-architecture. ++ * Mark amd64-only symbols as such. ++ * Minor rules cleanup. ++ ++ -- Dmitry Smirnov Sat, 19 Apr 2014 15:56:37 +1000 ++ ++ceph (0.79-2) experimental; urgency=low ++ ++ [ James Page ] ++ * d/p/modules.patch,d/ceph.install: Mark all jerasure plugins as modules ++ and ensure they are all installed. ++ ++ [ Dmitry Smirnov ] ++ * Patchworks: ++ - removed unused "defaults-leveldb-osd.patch". ++ + improved description of "modules.patch". Thanks, James Page. ++ + added new backported patches [#5469, #8008, _1606, spelling]. ++ * Added .symbols and "dh_makeshlibs -V" shlibs tightening (Closes: #744382). ++ * README.Debian: added note regarding kernel client mount option. ++ * copyright: added license for man files. ++ * control: "Suggests: logrotate". ++ ++ -- Dmitry Smirnov Fri, 18 Apr 2014 18:27:01 +1000 ++ ++ceph (0.79-1) experimental; urgency=low ++ ++ * New upstream release [April 2014]. ++ * Tighten dependency on ceph-common. ++ * Install pm-suspend handler to stop/start ceph services on suspend/resume. ++ * New (inactive) patch to bump OSD's leveldb defaults. ++ * Patches dropped (applied-upstream): ++ - init.patch ++ - logrotate.patch ++ - fix-defaultweight.patch ++ * Refreshed "modules.patch". ++ ++ -- Dmitry Smirnov Tue, 08 Apr 2014 16:52:04 +1000 ++ ++ceph (0.78-2) experimental; urgency=low ++ ++ * Standards to 3.9.5. ++ * debian/copyright: reviewed and updated. ++ * ceph-test: added lintian-override for "binary-without-manpage". ++ * Patchworks: ++ + refreshed/renamed/reordered "virtualenv-never-download.patch". ++ + new "init.patch" for init.d scripts lintianisation. ++ + new "logrotate.patch" to avoid rotating empty logs. ++ + new "fix-defaultweight.patch" to fix weight calculation on OSD start. ++ + new "gcj.patch" with partial fix to FTBFS with gcj-jdk. ++ * Use symlinks to simplify installation of init.d and logrotate scripts. ++ * Added retrospective changelog entry to mention new B-D "libblkid-dev". ++ * Added "debian/clean file". ++ * Added "README.Debian" file with some hopefully useful notes. ++ * Added "mount.fuse.ceph.8" man page. ++ * rules: ++ + "dh --with" optimised. ++ + set JAVAC to prevent FTBFS due to incorrect use of 'gcj', when detected. ++ + verbose mode for 'cp' and 'rm' commands. ++ + build with "--as-needed" to minimise needless linking. ++ * control: ++ + lintian/duplicate-short-description + consistent capitalisation. ++ + removed needless versioned dependencies from Build-Depends. ++ + added myself to Uploaders. ++ ++ -- Dmitry Smirnov Tue, 25 Mar 2014 07:17:40 +1100 ++ ++ceph (0.78-1) experimental; urgency=medium ++ ++ * New upstream release: ++ - d/control: Add "xfslib-dev" and "libblkid-dev" to BD's. ++ - d/*: Sync relevant packaging changes from upstream. ++ - d/p/*: Drop upstreamed patches. ++ - d/p/modules.patch: Mark libcls_user.so and libec_jerasure.so as modules. ++ - d/ceph.install: Only install libec_jerasure.so. ++ * d/ceph-test.install: Install test binaries to /usr/lib/ceph/bin; they ++ really don't need to be installed on the default path. ++ * d/{ceph|radosgw|ceph-mds}.lintian-overrides: Add overrides for intentional ++ difference in naming and structure between upstart configurations and ++ init.d scripts. ++ ++ -- James Page Sat, 22 Mar 2014 18:27:40 +0000 ++ ++ceph (0.72.2-3) unstable; urgency=medium ++ ++ * Team upload. ++ ++ [ James Page ] ++ * d/ceph-test.install: Install test binaries to /usr/lib/ceph/bin; they ++ really don't need to be installed on the default path. ++ ++ [ Dmitry Smirnov ] ++ * Tightened shlibs with "dh_makeshlibs -V" (Closes: #679686). ++ ++ -- Dmitry Smirnov Mon, 14 Apr 2014 17:28:20 +1000 ++ ++ceph (0.72.2-2) unstable; urgency=medium ++ ++ * d/radosgw.{postinst,postrm,preinst}: Handle renaming of radosgw ++ upstart configuration on upgrade@0.72.1-3. ++ * d/{ceph|ceph-mds|radosgw}.{postinst|prerm}: Check to ensure that system ++ is running upstart before trying to start/stop upstart configurations ++ (Closes: #734241, #738845, #738845). ++ ++ -- James Page Sat, 08 Mar 2014 16:48:28 +0000 ++ ++ceph (0.72.2-1) unstable; urgency=medium ++ ++ * New upstream release. ++ ++ -- James Page Wed, 01 Jan 2014 09:32:03 +0000 ++ ++ceph (0.72.1-3) unstable; urgency=low ++ ++ * d/rules,ceph.install: Correct install paths for ceph-* helpers. ++ * d/p/modules: Mark libcls_kvs.so as module. ++ * d/rules: Rename radosgw upstart configuration to radosgw-instance to ++ avoid namespace conflict with init script which breaks backwards ++ compatibility (LP: #1255464). ++ ++ -- James Page Wed, 27 Nov 2013 10:52:48 +0000 ++ ++ceph (0.72.1-2) unstable; urgency=low ++ ++ * Fix upgrade failures from ceph < 0.67.3-1 (Closes: #728164): ++ - d/control: ceph-mds Breaks/Replaces ceph (<< 0.67.3-1). ++ - d/control: ceph-fs-common Breaks/Replaces ceph-common (<< 0.67.3-1). ++ * d/rules,control: Use google-perftools on armhf and powerpc archs. ++ ++ -- James Page Mon, 25 Nov 2013 10:13:19 +0000 ++ ++ceph (0.72.1-1) unstable; urgency=low ++ ++ * New upstream stable release: ++ - d/ceph-test.install: Add new ceph_filestore_tool, ceph-kvstore-tool ++ and ceph_test_cls_hello binaries, drop ceph_test_store_tool. ++ - d/ceph-common.install: Add new ceph-post-file binary and manpage. ++ - d/ceph.install: Tweaked install path /usr/sbin -> /sbin. ++ - d/control: Add new BD's on python-nose and yasm. ++ - d/copyright: Updates inline with changes in codebase. ++ - d/ceph.install,rules: Install rbdmap init file using dh_installinit. ++ - Refresh patches. ++ * d/control,rules: Disable unit testing; it requires a forked version of ++ cram and is still trying to download dependencies using virtualenv. ++ ++ -- James Page Fri, 22 Nov 2013 13:02:29 +0000 ++ ++ceph (0.67.3-1) unstable; urgency=low ++ ++ [ Laszlo Boszormenyi ] ++ * New upstream release (Closes: #693866, #705262). ++ * Update debian/copyright. ++ * Sync with Ubuntu. ++ ++ [ James Page ] ++ * d/control,rules,libcephfs-{java,jni}: Enable Java CephFS library, ++ add new BD's on javahelper and default-jdk, add dbg package. ++ * d/control: Add new BD on libboost-thread-dev for RADOS Gateway ++ keystone integration. ++ * d/{control,obsync.install}: Drop obsync package inline with ++ upstream. ++ * d/librbd-dev.install: Pickup new features.h file. ++ * Remove manual calls to ldconfig: ++ - d/lib{rados2|rbd1|cephfs1}.post*: Dropped - all these do is call ++ ldconfig which will automatically be done. ++ - d/rules: Let dh_makeshlibs do its magic with postinst/postrm. ++ * d/tests/*: Added autopkgtests for librbd, librados, python-ceph ++ and the ceph CLI. ++ * d/control: Fix versions of librbd1, librados2 and libcephfs1 for ++ python-ceph as it requires an exact version match. ++ * d/ceph.docs: Drop - README from upstream is only useful for developers ++ (Closes: #722957). ++ * d/rules: Drop --upstart-only from dh_installinit calls for upstart ++ configurations; this is deprecated in Ubuntu and not support in Debian. ++ * d/rules: Exclude jni package from shlibs generation to avoid pointless ++ ldconfig calls in maintainer scripts. ++ ++ [ Bastian Blank ] ++ * Use debhelper 9. ++ * Use dh-autoreconf. ++ * Install files from source tree if possible. ++ * Run test-suite: ++ - Build-depend on python-virtualenv. ++ - Ask virtualenv to never download anything. ++ * Fix clean target. ++ * Properly mark library modules: ++ - Don't longer exclude them from stripping. ++ * Drop all libtool .la files. ++ * Generate python dependencies. ++ * Don't exclude stuff from shlibs generation. ++ ++ -- Laszlo Boszormenyi (GCS) Tue, 01 Oct 2013 02:29:08 +0200 ++ ++ceph (0.48-1) unstable; urgency=low ++ ++ * New upstream release, the first with long-term support. ++ * As gceph dropped by upstream, remove it from packaging. ++ * Build with hardening enabled and build-conflict with libcryptopp not to ++ mix up with libnss. ++ * Use symbol versioning (closes: #679686). ++ * Update debian/watch to GitHub tags. ++ ++ -- Laszlo Boszormenyi (GCS) Sat, 07 Jul 2012 07:53:40 +0200 ++ ++ceph (0.47.2-1) unstable; urgency=low ++ ++ * New upstream release. ++ * Use system leveldb (closes: #667907). ++ * Remove librgw1 , librgw-dev and librgw1-dbg and add rest-bench and ++ rest-bench-dbg packages. ++ * Backport leveldb build fixes from upstream git as ++ fix_leveldb_dep_for_system_library_case.patch and ++ fix_leveldb_includes_for_system_library_case.patch . ++ * Update packaging. ++ * Sync with Ubuntu: switch build-dependency from libcryptopp to libnss as ++ libcryptopp is not seeded. ++ ++ -- Laszlo Boszormenyi (GCS) Sun, 03 Jun 2012 13:37:52 +0200 ++ ++ceph (0.44.1-1) unstable; urgency=low ++ ++ * New upstream release. ++ ++ -- Laszlo Boszormenyi (GCS) Fri, 06 Apr 2012 01:10:15 +0200 ++ ++ceph (0.43-1) unstable; urgency=low ++ ++ * New upstream release, now creates /var/run/ceph on each start ++ (closes: #660238). ++ * Update debian/copyright . ++ ++ -- Laszlo Boszormenyi (GCS) Sun, 26 Feb 2012 04:07:02 +0100 ++ ++ceph (0.41-1) unstable; urgency=low ++ ++ * New upstream release. ++ ++ -- Laszlo Boszormenyi (GCS) Sun, 05 Feb 2012 10:07:38 +0100 ++ ++ceph (0.40-1) unstable; urgency=low ++ ++ * New upstream release (closes: #652037). ++ * Adjust copyright to match upstream source changes. ++ ++ -- Laszlo Boszormenyi (GCS) Sat, 14 Jan 2012 12:01:30 +0100 ++ ++ceph (0.38-1) unstable; urgency=low ++ ++ * New upstream release (closes: #647764), missingok is now part of logrotate ++ directives (closes: #645651). ++ * Rename ceph-client-tools package to ceph-common , libceph-dev to ++ libcephfs-dev and libceph1{,-dbg} ones to libcephfs1{,-dbg} respectively. ++ * Update upstream VCS locations. ++ ++ -- Laszlo Boszormenyi (GCS) Sun, 27 Nov 2011 21:40:52 +0100 ++ ++ceph (0.35-1) unstable; urgency=low ++ ++ * New upstream release. ++ ++ -- Laszlo Boszormenyi (GCS) Sat, 24 Sep 2011 16:51:57 +0200 ++ ++ceph (0.34-1) unstable; urgency=low ++ ++ * New upstream release (closes: #638714). ++ * Make librbd-dev depends on librados-dev as it uses headers from the latter ++ (closes: #636845). ++ * Add new binary packages, gceph, gceph-dbg and obsync . The libcrush ones ++ removed. ++ * Change to quilt source format and tune packaging. ++ ++ -- Laszlo Boszormenyi (GCS) Sun, 28 Aug 2011 15:56:16 +0200 ++ ++ceph (0.27-1.1) unstable; urgency=low ++ ++ * Non-maintainer upload. ++ * Remove references to other libraries from dependency_libs field ++ (closes: #621208). ++ ++ -- Luk Claes Sat, 28 May 2011 22:28:48 +0200 ++ ++ceph (0.27-1) unstable; urgency=low ++ ++ * New upstream release. ++ ++ -- Laszlo Boszormenyi (GCS) Mon, 25 Apr 2011 10:09:05 +0200 ++ ++ceph (0.25.2-1) unstable; urgency=low ++ ++ * New upstream release. ++ * Make Ceph cross buildable (closes: #618939), thanks to Hector Oron. ++ * Disable libatomic-ops on ARMv4t (armel) archs to prevent FTBFS ++ (closes: #615235), thanks go to Hector Oron again. ++ * Rename librados1{,-dbg,-dev} packages to librados2{,-dbg,-dev} ones; ++ conflict with and replace the former ones. ++ * Add librbd1 and librbd-dev packages. ++ ++ -- Laszlo Boszormenyi (GCS) Sun, 27 Mar 2011 15:51:23 +0200 ++ ++ceph (0.24.3-2) unstable; urgency=low ++ ++ * Make Ceph Linux only and build on all Linux archs (closes: #614890). ++ * Support parallel building via DEB_BUILD_OPTIONS . ++ * Add watch file, thanks to Clint Byrum (closes: #615021). ++ * Tune packaging. ++ ++ -- Laszlo Boszormenyi (GCS) Fri, 25 Feb 2011 15:17:26 +0100 ++ ++ceph (0.24.3-1) unstable; urgency=low ++ ++ * New upstream bugfix release. ++ ++ -- Laszlo Boszormenyi (GCS) Sat, 19 Feb 2011 12:25:43 +0100 ++ ++ceph (0.24.2-1) unstable; urgency=low ++ ++ * New upstream bugfix release. ++ ++ -- Laszlo Boszormenyi (GCS) Sat, 29 Jan 2011 15:25:14 +0100 ++ ++ceph (0.24.1-1) unstable; urgency=low ++ ++ * New upstream bugfix release. ++ ++ -- Laszlo Boszormenyi (GCS) Tue, 11 Jan 2011 22:23:18 +0100 ++ ++ceph (0.24-1) unstable; urgency=low ++ ++ * New upstream release. ++ ++ -- Laszlo Boszormenyi (GCS) Wed, 01 Dec 2010 09:26:25 -0800 ++ ++ceph (0.23.1-1) experimental; urgency=low ++ ++ * Initial release (Closes: #506040) ++ ++ -- Sage Weil Sun, 21 Nov 2010 15:22:21 -0800 diff --cc debian/clean index 000000000,000000000..8638ac91a new file mode 100644 --- /dev/null +++ b/debian/clean @@@ -1,0 -1,0 +1,32 @@@ ++configure ++src/rocksdb/util/build_version.cc ++src/pybind/*.pyc ++src/test/pybind/*.pyc ++src/rapidjson/thirdparty/gtest/googlemock/msvc/2005/gmock.sln ++src/rapidjson/thirdparty/gtest/googlemock/msvc/2005/gmock.vcproj ++src/rapidjson/thirdparty/gtest/googlemock/msvc/2005/gmock_config.vsprops ++src/rapidjson/thirdparty/gtest/googlemock/msvc/2005/gmock_main.vcproj ++src/rapidjson/thirdparty/gtest/googlemock/msvc/2005/gmock_test.vcproj ++src/rapidjson/thirdparty/gtest/googlemock/msvc/2010/gmock.sln ++src/rapidjson/thirdparty/gtest/googlemock/msvc/2010/gmock.vcxproj ++src/rapidjson/thirdparty/gtest/googlemock/msvc/2010/gmock_config.props ++src/rapidjson/thirdparty/gtest/googlemock/msvc/2010/gmock_main.vcxproj ++src/rapidjson/thirdparty/gtest/googlemock/msvc/2010/gmock_test.vcxproj ++src/rapidjson/thirdparty/gtest/googletest/codegear/gtest.cbproj ++src/rapidjson/thirdparty/gtest/googletest/codegear/gtest.groupproj ++src/rapidjson/thirdparty/gtest/googletest/codegear/gtest_all.cc ++src/rapidjson/thirdparty/gtest/googletest/codegear/gtest_link.cc ++src/rapidjson/thirdparty/gtest/googletest/codegear/gtest_main.cbproj ++src/rapidjson/thirdparty/gtest/googletest/codegear/gtest_unittest.cbproj ++src/rapidjson/thirdparty/gtest/googletest/msvc/gtest-md.sln ++src/rapidjson/thirdparty/gtest/googletest/msvc/gtest-md.vcproj ++src/rapidjson/thirdparty/gtest/googletest/msvc/gtest.sln ++src/rapidjson/thirdparty/gtest/googletest/msvc/gtest.vcproj ++src/rapidjson/thirdparty/gtest/googletest/msvc/gtest_main-md.vcproj ++src/rapidjson/thirdparty/gtest/googletest/msvc/gtest_main.vcproj ++src/rapidjson/thirdparty/gtest/googletest/msvc/gtest_prod_test-md.vcproj ++src/rapidjson/thirdparty/gtest/googletest/msvc/gtest_prod_test.vcproj ++src/rapidjson/thirdparty/gtest/googletest/msvc/gtest_unittest-md.vcproj ++src/rapidjson/thirdparty/gtest/googletest/msvc/gtest_unittest.vcproj ++debian/ceph-common.logrotate ++debian/radosgw.init diff --cc debian/control index 000000000,000000000..4c08a045f new file mode 100644 --- /dev/null +++ b/debian/control @@@ -1,0 -1,0 +1,1200 @@@ ++Source: ceph ++Section: admin ++Priority: optional ++Maintainer: Ceph Packaging Team ++Uploaders: ++ James Page , ++ Gaudenz Steinlin , ++ Bernd Zeimetz , ++ Thomas Goirand , ++Build-Depends: ++ clang [armhf mipsel armel m68k sh4], ++ cmake, ++ cython3, ++ debhelper-compat (= 11), ++ default-jdk, ++ dh-exec, ++ dh-python, ++ dpkg-dev (>= 1.16.1~), ++ gperf, ++ javahelper, ++ junit4, ++ libaio-dev, ++ libbabeltrace-ctf-dev, ++ libbabeltrace-dev, ++ libblkid-dev (>= 2.17), ++ libboost-atomic-dev (>= 1.74.0), ++ libboost-chrono-dev (>= 1.74.0), ++ libboost-context-dev (>= 1.74.0) [!ia64 !m68k !ppc64 !sh4 !sparc64 !x32 !alpha], ++ libboost-coroutine-dev (>= 1.74.0) [!ia64 !m68k !ppc64 !sh4 !sparc64 !x32 !alpha], ++ libboost-date-time-dev (>= 1.74.0), ++ libboost-filesystem-dev (>= 1.74.0), ++ libboost-iostreams-dev (>= 1.74.0), ++ libboost-program-options-dev (>= 1.74.0), ++ libboost-python-dev (>= 1.74.0), ++ libboost-random-dev (>= 1.74.0), ++ libboost-regex-dev (>= 1.74.0), ++ libboost-system-dev (>= 1.74.0), ++ libboost-test-dev (>= 1.74.0), ++ libboost-thread-dev (>= 1.74.0), ++ libboost-timer-dev (>= 1.74.0), ++ libbz2-dev, ++ libc-ares-dev, ++ libcap-ng-dev, ++ libcrypto++-dev, ++ libcryptsetup-dev, ++ libcunit1-dev, ++ libcurl4-gnutls-dev, ++ libedit-dev, ++ libexpat1-dev, ++ libfmt-dev, ++ libfuse-dev, ++ libgnutls28-dev, ++ libgoogle-perftools-dev [amd64 arm64 armel armhf i386 mips64el mipsel ppc64 ppc64el riscv64 powerpc s390x], ++ libhwloc-dev, ++ libibverbs-dev, ++ libicu-dev, ++ libkeyutils-dev, ++ libldap2-dev, ++ libleveldb-dev, ++ liblua5.3-dev, ++ liblz4-dev (>= 0.0~r131), ++ libncurses-dev, ++ libnl-3-dev, ++ libnl-genl-3-dev, ++ libnss3-dev, ++ libnuma-dev, ++ liboath-dev, ++ libpciaccess-dev, ++ libpmem-dev [amd64 arm64 ppc64el], ++ libpmemobj-dev [amd64 arm64 ppc64el], ++ libprotobuf-dev, ++ librabbitmq-dev, ++ librdmacm-dev, ++ libsctp-dev, ++ libsnappy-dev, ++ libsqlite3-dev, ++ libssl-dev, ++ libtool, ++ libudev-dev, ++ liburing-dev, ++ libxml2-dev, ++ libyaml-cpp-dev, ++ lsb-release, ++ nasm [amd64], ++ pkg-config, ++ protobuf-compiler, ++ python3-dev, ++ python3-cherrypy3, ++ python3-pecan, ++ python3-setuptools, ++ python3-sphinx, ++ ragel, ++ systemtap-sdt-dev, ++ tox, ++ uuid-runtime, ++ valgrind [amd64 armhf arm64 i386 mips64el mipsel ppc64 ppc64el s390x], ++ virtualenv, ++ xfslibs-dev, ++ zlib1g-dev, ++Standards-Version: 4.2.1 ++Vcs-Git: https://salsa.debian.org/ceph-team/ceph.git ++Vcs-Browser: https://salsa.debian.org/ceph-team/ceph ++Homepage: http://ceph.com/ ++ ++Package: ceph ++Architecture: linux-any ++Depends: ++ ceph-mgr (= ${binary:Version}), ++ ceph-mon (= ${binary:Version}), ++ ceph-osd (= ${binary:Version}), ++ ${misc:Depends}, ++Suggests: ++ ceph-mds (= ${binary:Version}), ++Description: distributed storage and file system ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ ++Package: ceph-base ++Architecture: linux-any ++Depends: ++ binutils, ++ ceph-common (= ${binary:Version}), ++ cryptsetup-bin | cryptsetup, ++ gdisk, ++ hdparm | sdparm, ++ parted, ++ uuid-runtime, ++ xfsprogs, ++ ${misc:Depends}, ++ ${python3:Depends}, ++ ${shlibs:Depends}, ++Pre-Depends: ++ ${misc:Pre-Depends}, ++Recommends: ++ ceph-mds (= ${binary:Version}), ++ chrony | time-daemon | ntp, ++ librados2 (= ${binary:Version}), ++ librbd1 (= ${binary:Version}), ++Suggests: ++ btrfs-tools, ++ logrotate, ++Description: common ceph daemon libraries and management tools ++ Ceph is a distributed storage system designed to provide excellent ++ performance, reliability, and scalability. ++ . ++ This package contains the libraries and management tools that are common among ++ the Ceph server daemons (ceph-mon, ceph-mgr, ceph-osd, ceph-mds). These tools ++ are necessary for creating, running, and administering a Ceph storage cluster. ++ ++Package: ceph-base-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ ceph-base (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for ceph-base ++ Ceph is a distributed storage system designed to provide excellent ++ performance, reliability, and scalability. ++ . ++ This package contains the debugging symbols for ceph-base. ++ ++Package: ceph-common ++Architecture: linux-any ++Depends: ++ librbd1 (= ${binary:Version}), ++ python3-cephfs (= ${binary:Version}), ++ python3-prettytable, ++ python3-rados (= ${binary:Version}), ++ python3-rbd (= ${binary:Version}), ++ python3-requests, ++ ${misc:Depends}, ++ ${python3:Depends}, ++ ${shlibs:Depends}, ++Conflicts: ++ ceph-client-tools, ++Suggests: ++ ceph, ++ ceph-mds, ++Description: common utilities to mount and interact with a ceph storage cluster ++ Ceph is a distributed storage and file system designed to provide ++ excellent performance, reliability, and scalability. This is a collection ++ of common tools that allow one to interact with and administer a Ceph cluster. ++ ++Package: ceph-common-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ ceph-common (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for ceph-common ++ Ceph is a distributed storage system designed to provide excellent ++ performance, reliability, and scalability. ++ . ++ This package contains the debugging symbols for ceph-common. ++ ++Package: ceph-fuse ++Architecture: amd64 ++Depends: ++ python3, ++ ${misc:Depends}, ++ ${python3:Depends}, ++ ${shlibs:Depends}, ++Recommends: ++ fuse, ++Description: FUSE-based client for the Ceph distributed file system ++ Ceph is a distributed network file system designed to provide ++ excellent performance, reliability, and scalability. This is a ++ FUSE-based client that allows one to mount a Ceph file system without ++ root privileges. ++ . ++ Because the FUSE-based client has certain inherent performance ++ limitations, it is recommended that the native Linux kernel client ++ be used if possible. If it is not practical to load a kernel module ++ (insufficient privileges, older kernel, etc.), then the FUSE client will ++ do. ++ ++Package: ceph-fuse-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ ceph-fuse (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for ceph-fuse ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. This is a ++ FUSE-based client that allows one to mount a Ceph file system without ++ root privileges. ++ . ++ This package contains the debugging symbols for ceph-fuse. ++ ++Package: ceph-grafana-dashboards ++Architecture: all ++Depends: ++ ${misc:Depends}, ++Description: grafana dashboards for the ceph dashboard ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains Grafana dashboards that are used by the Ceph Dashboard ++ for monitoring. ++ ++Package: ceph-immutable-object-cache ++Architecture: linux-any ++Depends: ++ ceph-common (= ${binary:Version}), ++ librados2 (= ${binary:Version}), ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Description: Ceph daemon for immutable object cache ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. This is a daemon for immutable ++ object cache. ++ ++Package: ceph-immutable-object-cache-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ ceph-immutable-object-cache (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for ceph-immutable-object-cache ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. This is a daemon for immutable ++ object cache. ++ . ++ This package contains the debugging symbols for ceph-immutable-object-cache. ++ ++Package: ceph-mds ++Architecture: linux-any ++Depends: ++ ceph, ++ ceph-base (= ${binary:Version}), ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Recommends: ++ ceph-common, ++ ceph-fuse, ++ libcephfs2, ++Description: metadata server for the ceph distributed file system ++ Ceph is a distributed storage and network file system designed to ++ provide excellent performance, reliability, and scalability. ++ . ++ This package contains the metadata server daemon, which is used to ++ create a distributed file system on top of the ceph storage cluster. ++ ++Package: ceph-mds-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ ceph-mds (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for ceph-mds ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains the debugging symbols for ceph-mds. ++ ++Package: ceph-mgr ++Architecture: linux-any ++Depends: ++ ceph-base (= ${binary:Version}), ++ ceph-mgr-modules-core (<< ${source:Version}.1~), ++ ceph-mgr-modules-core (>= ${source:Version}), ++ python3-bcrypt, ++ python3-cherrypy3, ++ python3-jwt, ++ python3-openssl, ++ python3-pecan, ++ python3-requests, ++ python3-werkzeug, ++ ${misc:Depends}, ++ ${python3:Depends}, ++ ${shlibs:Depends}, ++Suggests: ++ ceph-mgr-dashboard, ++ ceph-mgr-diskprediction-local, ++ ceph-mgr-rook, ++Description: manager for the ceph distributed file system ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains the manager daemon, which is used to expose high ++ level management and monitoring functionality. ++ ++Package: ceph-mgr-cephadm ++Architecture: all ++Depends: ++ ceph-mgr (<< ${source:Version}.1~), ++ ceph-mgr (>= ${source:Version}), ++ cephadm, ++ openssh-client, ++ python3-jinja2, ++ ${misc:Depends}, ++ ${python3:Depends}, ++Description: cephadm orchestrator module for ceph-mgr ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains the CEPHADM module for ceph-mgr's orchestration ++ functionality, to allow ceph-mgr to perform orchestration functions ++ over a standard SSH connection. ++ ++Package: ceph-mgr-dashboard ++Architecture: all ++Depends: ++ ceph-mgr (>= ${binary:Version}), ++ python3-bcrypt, ++ python3-cherrypy3, ++ python3-distutils, ++ python3-jwt, ++ python3-openssl, ++ python3-routes, ++ python3-werkzeug, ++ ${misc:Depends}, ++ ${python3:Depends}, ++ ${shlibs:Depends}, ++Description: dashboard plugin for ceph-mgr ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package provides a ceph-mgr plugin, providing a web-based ++ application to monitor and manage many aspects of a Ceph cluster and ++ related components. ++ . ++ See the Dashboard documentation at http://docs.ceph.com/ for details ++ and a detailed feature overview. ++ ++Package: ceph-mgr-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ ceph-mgr (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for ceph-mgr ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains the debugging symbols for ceph-mgr. ++ ++Package: ceph-mgr-diskprediction-local ++Architecture: all ++Depends: ++ ceph-mgr (>= ${binary:Version}), ++ python3-numpy, ++ python3-scipy, ++ python3-sklearn, ++ ${misc:Depends}, ++ ${python3:Depends}, ++ ${shlibs:Depends}, ++Description: diskprediction-local plugin for ceph-mgr ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains the diskprediction_local plugin for the ceph-mgr ++ daemon, which helps predict disk failures. ++ ++Package: ceph-mgr-k8sevents ++Architecture: all ++Depends: ++ ceph-mgr (>= ${binary:Version}), ++ python3-kubernetes, ++ ${misc:Depends}, ++ ${python3:Depends}, ++Description: kubernetes events plugin for ceph-mgr ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains the k8sevents plugin, to allow ceph-mgr to send ++ ceph related events to the kubernetes events API, and track all events ++ that occur within the rook-ceph namespace. ++ ++Package: ceph-mgr-modules-core ++Architecture: all ++Depends: ++ python3-dateutil, ++ python3-openssl, ++ ${misc:Depends}, ++ ${python3:Depends}, ++ ${shlibs:Depends}, ++Replaces: ++ ceph-mgr (<< 15.1.0), ++Breaks: ++ ceph-mgr (<< 15.1.0), ++Description: ceph manager modules which are always enabled ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains a set of core ceph-mgr modules which are always ++ enabled. ++ ++Package: ceph-mgr-rook ++Architecture: all ++Depends: ++ ceph-mgr (>= ${binary:Version}), ++ python3-six, ++ ${misc:Depends}, ++ ${python3:Depends}, ++ ${shlibs:Depends}, ++Description: rook plugin for ceph-mgr ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains the rook plugin for ceph-mgr's orchestration ++ functionality, to allow ceph-mgr to install and configure ceph using ++ Rook. ++ ++Package: ceph-mon ++Architecture: linux-any ++Depends: ++ ceph-base (= ${binary:Version}), ++ ${misc:Depends}, ++ ${python3:Depends}, ++ ${shlibs:Depends}, ++Description: monitor server for the ceph storage system ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains the cluster monitor daemon for the Ceph storage ++ system. One or more instances of ceph-mon form a Paxos part-time parliament ++ cluster that provides extremely reliable and durable storage of cluster ++ membership, configuration, and state. ++ ++Package: ceph-mon-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ ceph-mon (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for ceph-mon ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains the debugging symbols for ceph-mon. ++ ++Package: ceph-osd ++Architecture: linux-any ++Depends: ++ ceph-base (= ${binary:Version}), ++ lvm2, ++ smartmontools, ++ sudo, ++ ${misc:Depends}, ++ ${python3:Depends}, ++ ${shlibs:Depends}, ++Suggests: ++ nvme-cli, ++Pre-Depends: ++ ceph-common (= ${binary:Version}), ++Description: OSD server for the ceph storage system ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains the Object Storage Daemon for the Ceph storage system. ++ It is responsible for storing objects on a local file system ++ and providing access to them over the network. ++ ++Package: ceph-osd-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ ceph-osd (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for ceph-osd ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains the debugging symbols for ceph-osd. ++ ++Package: ceph-prometheus-alerts ++Architecture: all ++Depends: ++ ${misc:Depends}, ++Description: prometheus alerts for the ceph dashboard ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains alerts used for prometheus to interact with the ++ Ceph Dashboard. ++ ++Package: ceph-resource-agents ++Architecture: all ++Priority: optional ++Recommends: ++ pacemaker, ++Depends: ++ ceph (>= ${binary:Version}), ++ resource-agents, ++ ${misc:Depends}, ++Description: OCF-compliant resource agents for Ceph ++ Ceph is a distributed storage and network file system designed to provide ++ excellent performance, reliability, and scalability. ++ . ++ This package contains the resource agents (RAs) which integrate ++ Ceph with OCF-compliant cluster resource managers, ++ such as Pacemaker. ++ ++Package: ceph-test ++Architecture: linux-any ++Depends: ++ ceph-common (= ${binary:Version}), ++ curl, ++ jq, ++ socat, ++ xmlstarlet, ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Description: Ceph test and benchmarking tools ++ This package contains tools for testing and benchmarking Ceph. ++ ++Package: cephadm ++Architecture: linux-any ++Recommends: ++ podman (>= 2.0.2) | docker.io, ++Depends: ++ lvm2, ++ ${misc:Depends}, ++ ${python3:Depends}, ++Description: utility to bootstrap ceph daemons with systemd and containers ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ The cephadm utility is used to bootstrap a Ceph cluster and to manage ++ ceph daemons deployed with systemd and containers. ++ ++Package: cephfs-mirror ++Architecture: linux-any ++Depends: ++ ceph-common (= ${binary:Version}), ++ libcephfs2 (= ${binary:Version}), ++ librados2 (= ${binary:Version}), ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Description: Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. This is a daemon for mirroring CephFS ++ directory snapshots between Ceph clusters. ++ ++Package: cephfs-mirror-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ cephfs-mirror (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for cephfs-mirror ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. This is a daemon for mirroring CephFS ++ directory snapshots between Ceph clusters. ++ ++Package: cephfs-shell ++Architecture: all ++Depends: ++ ${misc:Depends}, ++ ${python3:Depends}, ++Description: interactive shell for the Ceph distributed file system ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. This is an interactive tool that ++ allows accessing a Ceph file system without mounting it by providing ++ a nice pseudo-shell which works like an FTP client. ++ . ++ This package contains a CLI for interacting with the CephFS. ++ ++Package: cephfs-top ++Architecture: all ++Depends: ++ ${misc:Depends}, ++ ${python3:Depends}, ++Description: This package provides a top(1) like utility to display various ++ filesystem metrics in realtime. ++ . ++ This package contains utility for displaying filesystem metrics. ++ ++Package: libcephfs-dev ++Architecture: linux-any ++Section: libdevel ++Depends: ++ libcephfs2 (= ${binary:Version}), ++ ${misc:Depends}, ++Conflicts: ++ libceph-dev, ++ libceph1-dev, ++ libcephfs2-dev, ++Replaces: ++ libceph-dev, ++ libceph1-dev, ++ libcephfs2-dev, ++Description: Ceph distributed file system client library (development files) ++ Ceph is a distributed network file system designed to provide ++ excellent performance, reliability, and scalability. This is a ++ shared library allowing applications to access a Ceph distributed ++ file system via a POSIX-like interface. ++ . ++ This package contains development files needed for building applications that ++ link against libcephfs2. ++ ++Package: libcephfs-java ++Architecture: all ++Section: java ++Depends: ++ libcephfs-jni (>= ${binary:Version}), ++ ${java:Depends}, ++ ${misc:Depends}, ++Description: Java library for the Ceph File System ++ Ceph is a distributed storage system designed to provide excellent ++ performance, reliability, and scalability. ++ . ++ This package contains the Java library for interacting with the Ceph ++ File System. ++ ++Package: libcephfs-jni ++Architecture: linux-any ++Section: libs ++Depends: ++ libcephfs2 (= ${binary:Version}), ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Description: Java Native Interface library for CephFS Java bindings ++ Ceph is a distributed storage system designed to provide excellent ++ performance, reliability, and scalability. ++ . ++ This package contains the Java Native Interface library for interacting ++ with the Ceph File System. ++ ++Package: libcephfs2 ++Architecture: linux-any ++Section: libs ++Conflicts: ++ libceph, ++ libceph1, ++ libcephfs, ++Replaces: ++ libceph, ++ libceph1, ++ libcephfs, ++Depends: ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Pre-Depends: ++ ${misc:Pre-Depends}, ++Description: Ceph distributed file system client library ++ Ceph is a distributed network file system designed to provide ++ excellent performance, reliability, and scalability. This is a ++ shared library allowing applications to access a Ceph distributed ++ file system via a POSIX-like interface. ++ ++Package: libcephfs2-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ libcephfs2 (= ${binary:Version}), ++ ${misc:Depends}, ++Conflicts: ++ libceph1-dbg, ++Replaces: ++ libceph1-dbg, ++Description: debugging symbols for libcephfs2 ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. This is a ++ shared library allowing applications to access a Ceph distributed ++ file system via a POSIX-like interface. ++ . ++ This package contains debugging symbols for libcephfs2. ++ ++Package: librados-dev ++Architecture: linux-any ++Section: libdevel ++Depends: ++ librados2 (= ${binary:Version}), ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Conflicts: ++ librados1-dev, ++ librados2-dev, ++Replaces: ++ librados1-dev, ++ librados2-dev, ++Description: RADOS distributed object store client library (development files) ++ RADOS is a reliable, autonomic distributed object storage cluster ++ developed as part of the Ceph distributed storage system. This is a ++ shared library allowing applications to access the distributed object ++ store using a simple file-like interface. ++ . ++ This package contains development files needed for building applications that ++ link against librados2. ++ ++Package: librados2 ++Architecture: linux-any ++Section: libs ++Conflicts: ++ librados, ++ librados1, ++Replaces: ++ librados, ++ librados1, ++Depends: ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Pre-Depends: ++ ${misc:Pre-Depends}, ++Description: RADOS distributed object store client library ++ RADOS is a reliable, autonomic distributed object storage cluster ++ developed as part of the Ceph distributed storage system. This is a ++ shared library allowing applications to access the distributed object ++ store using a simple file-like interface. ++ ++Package: librados2-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ librados2 (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for librados ++ RADOS is a reliable, autonomic distributed object storage cluster ++ developed as part of the Ceph distributed storage system. This is a ++ shared library allowing applications to access the distributed object ++ store using a simple file-like interface. ++ . ++ This package contains debugging symbols for librados. ++ ++Package: libradospp-dev ++Architecture: linux-any ++Section: libdevel ++Depends: ++ librados-dev (= ${binary:Version}), ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Description: RADOS distributed object store client C++ library (development files) ++ RADOS is a reliable, autonomic distributed object storage cluster ++ developed as part of the Ceph distributed storage system. This is a ++ shared library allowing applications to access the distributed object ++ store using a simple file-like interface. ++ . ++ This package contains development files needed for building C++ applications ++ that link against librados. ++ ++Package: libradosstriper-dev ++Architecture: linux-any ++Section: libdevel ++Depends: ++ libradosstriper1 (= ${binary:Version}), ++ ${misc:Depends}, ++Description: RADOS striping interface (development files) ++ libradosstriper is a striping interface built on top of the rados ++ library, allowing to stripe bigger objects onto several standard ++ rados objects using an interface very similar to the rados one. ++ . ++ This package contains development files needed for building applications that ++ link against libradosstriper. ++ ++Package: libradosstriper1 ++Architecture: linux-any ++Section: libs ++Depends: ++ librados2 (= ${binary:Version}), ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Description: RADOS striping interface ++ Striping interface built on top of the rados library, allowing ++ to stripe bigger objects onto several standard rados objects using ++ an interface very similar to the rados one. ++ ++Package: libradosstriper1-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ libradosstriper1 (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for libradosstriper ++ libradosstriper is a striping interface built on top of the rados ++ library, allowing to stripe bigger objects onto several standard ++ rados objects using an interface very similar to the rados one. ++ . ++ This package contains debugging symbols for libradosstriper. ++ ++Package: librbd-dev ++Architecture: linux-any ++Section: libdevel ++Depends: ++ librados-dev, ++ librbd1 (= ${binary:Version}), ++ ${misc:Depends}, ++Conflicts: ++ librbd1-dev, ++Replaces: ++ librbd1-dev, ++Description: RADOS block device client library (development files) ++ RBD is a block device striped across multiple distributed objects ++ in RADOS, a reliable, autonomic distributed object storage cluster ++ developed as part of the Ceph distributed storage system. This is a ++ shared library allowing applications to manage these block devices. ++ . ++ This package contains development files needed for building applications that ++ link against librbd1. ++ ++Package: librbd1 ++Architecture: linux-any ++Section: libs ++Depends: ++ librados2 (= ${binary:Version}), ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Pre-Depends: ++ ${misc:Pre-Depends}, ++Description: RADOS block device client library ++ RBD is a block device striped across multiple distributed objects ++ in RADOS, a reliable, autonomic distributed object storage cluster ++ developed as part of the Ceph distributed storage system. This is a ++ shared library allowing applications to manage these block devices. ++ ++Package: librbd1-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ librbd1 (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for librbd1 ++ RBD is a block device striped across multiple distributed objects ++ in RADOS, a reliable, autonomic distributed object storage cluster ++ developed as part of the Ceph distributed storage system. This is a ++ shared library allowing applications to manage these block devices. ++ . ++ This package contains debugging symbols for librbd1. ++ ++Package: librgw-dev ++Architecture: linux-any ++Section: libdevel ++Depends: ++ librados-dev (= ${binary:Version}), ++ librgw2 (= ${binary:Version}), ++ ${misc:Depends}, ++Description: RADOS client library (development files) ++ RADOS is a distributed object store used by the Ceph distributed ++ storage system. This package provides a REST gateway to the ++ object store that aims to implement a superset of Amazon's S3 ++ service. ++ . ++ This package contains development files needed for building applications ++ that link against librgw2. ++ ++Package: librgw2 ++Architecture: linux-any ++Section: libs ++Depends: ++ librados2 (= ${binary:Version}), ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Description: RADOS Gateway client library ++ RADOS is a distributed object store used by the Ceph distributed ++ storage system. This package provides a REST gateway to the ++ object store that aims to implement a superset of Amazon's S3 ++ service. ++ . ++ This package contains the library interface and headers only. ++ ++Package: librgw2-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ librgw2 (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for librbd1 ++ RADOS is a distributed object store used by the Ceph distributed ++ storage system. This package provides a REST gateway to the ++ object store that aims to implement a superset of Amazon's S3 ++ service. ++ . ++ This package contains debugging symbols for librgw2. ++ ++Package: libsqlite3-mod-ceph ++Architecture: any ++Section: libs ++Depends: ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Description: SQLite3 VFS for Ceph ++ A SQLite3 VFS for storing and manipulating databases stored on Ceph's RADOS ++ distributed object store. ++ . ++ This packages contains the loadable extension module for SQLite3. ++ ++Package: libsqlite3-mod-ceph-dbg ++Architecture: any ++Section: debug ++Depends: ++ libsqlite3-0-dbgsym, ++ libsqlite3-mod-ceph (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for libsqlite3-mod-ceph ++ A SQLite3 VFS for storing and manipulating databases stored on Ceph's RADOS ++ distributed object store. ++ . ++ This package contains debugging symbols for libsqlite3-mod-ceph. ++ ++Package: libsqlite3-mod-ceph-dev ++Architecture: any ++Section: libdevel ++Depends: ++ libsqlite3-dev, ++ libsqlite3-mod-ceph (= ${binary:Version}), ++ ${misc:Depends}, ++Description: SQLite3 VFS for Ceph (development files) ++ A SQLite3 VFS for storing and manipulating databases stored on Ceph's RADOS ++ distributed object store. ++ . ++ This package contains development files needed for building applications that ++ link against libsqlite3-mod-ceph. ++ ++ ++Package: python3-ceph ++Architecture: all ++Section: python ++Depends: ++ python3-cephfs (<< ${source:Version}.1~), ++ python3-cephfs (>= ${source:Version}), ++ python3-rados (<< ${source:Version}.1~), ++ python3-rados (>= ${source:Version}), ++ python3-rbd (<< ${source:Version}.1~), ++ python3-rbd (>= ${source:Version}), ++ python3-rgw (<< ${source:Version}.1~), ++ python3-rgw (>= ${source:Version}), ++ ${misc:Depends}, ++Description: Meta-package for all Python 3.x modules for the Ceph libraries ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package is a metapackage for all Ceph Python 3.x bindings. ++ ++Package: python3-ceph-argparse ++Architecture: linux-any ++Section: python ++Depends: ++ ${misc:Depends}, ++ ${python3:Depends}, ++Description: Python 3 utility libraries for Ceph CLI ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains types and routines for Python 3 used by the ++ Ceph CLI as well as the RESTful interface. ++ ++Package: python3-cephfs ++Architecture: linux-any ++Section: python ++Depends: ++ libcephfs2 (= ${binary:Version}), ++ python3-ceph-argparse (= ${binary:Version}), ++ python3-rados (= ${binary:Version}), ++ ${misc:Depends}, ++ ${python3:Depends}, ++ ${shlibs:Depends}, ++Description: Python 3 libraries for the Ceph libcephfs library ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains Python 3 libraries for interacting with Ceph's ++ CephFS file system client library. ++ ++Package: python3-rados ++Architecture: linux-any ++Section: python ++Depends: ++ librados2 (= ${binary:Version}), ++ ${misc:Depends}, ++ ${python3:Depends}, ++ ${shlibs:Depends}, ++Description: Python 3 libraries for the Ceph librados library ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains Python 3 libraries for interacting with Ceph's ++ RADOS object storage. ++ ++Package: python3-rbd ++Architecture: linux-any ++Section: python ++Depends: ++ librbd1 (>= ${binary:Version}), ++ ${misc:Depends}, ++ ${python3:Depends}, ++ ${shlibs:Depends}, ++Description: Python 3 libraries for the Ceph librbd library ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains Python 3 libraries for interacting with Ceph's ++ RBD block device library. ++ ++Package: python3-rgw ++Architecture: linux-any ++Section: python ++Depends: ++ librgw2 (>= ${binary:Version}), ++ python3-rados (= ${binary:Version}), ++ ${misc:Depends}, ++ ${python3:Depends}, ++ ${shlibs:Depends}, ++Description: Python 3 libraries for the Ceph librgw library ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains Python 3 libraries for interacting with Ceph's ++ RGW library. ++ ++Package: rados-objclass-dev ++Architecture: linux-any ++Section: libdevel ++Depends: ++ librados-dev (= ${binary:Version}), ++ ${misc:Depends}, ++Description: RADOS object class development kit. ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. ++ . ++ This package contains development files needed for building RADOS object class ++ plugins. ++ ++Package: radosgw ++Architecture: linux-any ++Depends: ++ ceph-common (= ${binary:Version}), ++ librgw2 (= ${binary:Version}), ++ mime-support, ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Suggests: ++ logrotate, ++Description: REST gateway for RADOS distributed object store ++ RADOS is a distributed object store used by the Ceph distributed ++ storage system. This package provides a REST gateway to the ++ object store that aims to implement a superset of Amazon's S3 ++ service as well as the OpenStack Object Storage ("Swift") API. ++ . ++ This package contains the proxy daemon and related tools only. ++ ++Package: radosgw-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ radosgw (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for radosgw ++ RADOS is a distributed object store used by the Ceph distributed ++ storage system. This package provides a REST gateway to the ++ object store that aims to implement a superset of Amazon's S3 ++ service as well as the OpenStack Object Storage ("Swift") API. ++ . ++ This package contains debugging symbols for radosgw. ++ ++Package: rbd-fuse ++Architecture: linux-any ++Depends: ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Recommends: ++ fuse, ++Description: FUSE-based rbd client for the Ceph distributed file system ++ Ceph is a distributed network file system designed to provide ++ excellent performance, reliability, and scalability. This is a ++ FUSE-based client that allows one to map Ceph rbd images as files. ++ ++Package: rbd-fuse-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ rbd-fuse (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for rbd-fuse ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. This is a ++ FUSE-based client that allows one to map Ceph rbd images as files. ++ . ++ This package contains the debugging symbols for rbd-fuse. ++ ++Package: rbd-mirror ++Architecture: linux-any ++Depends: ++ ceph-common (= ${binary:Version}), ++ librados2 (= ${binary:Version}), ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Description: Ceph daemon for mirroring RBD images ++ Ceph is a distributed storage system designed to provide excellent ++ performance, reliability, and scalability. ++ . ++ This package provides a daemon for mirroring RBD images between ++ Ceph clusters, streaming changes asynchronously. ++ ++Package: rbd-mirror-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ rbd-mirror (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for rbd-mirror ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. This is a ++ daemon for mirroring RBD images between Ceph clusters, streaming ++ changes asynchronously. ++ . ++ This package contains the debugging symbols for rbd-mirror. ++ ++Package: rbd-nbd ++Architecture: linux-any ++Depends: ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++Description: NBD-based rbd client for the Ceph distributed file system ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. This is a ++ NBD-based client that allows one to map Ceph rbd images as local ++ block device. ++ . ++ NBD base client that allows one to map Ceph rbd images as local ++ block device. ++ ++Package: rbd-nbd-dbg ++Architecture: linux-any ++Section: debug ++Depends: ++ rbd-nbd (= ${binary:Version}), ++ ${misc:Depends}, ++Description: debugging symbols for rbd-nbd ++ Ceph is a massively scalable, open-source, distributed ++ storage system that runs on commodity hardware and delivers object, ++ block and file system storage. This is a ++ NBD-based client that allows one to map Ceph rbd images as local ++ block device. ++ . ++ This package contains the debugging symbols for rbd-nbd. diff --cc debian/copyright index 000000000,000000000..33b9b850d new file mode 100644 --- /dev/null +++ b/debian/copyright @@@ -1,0 -1,0 +1,1194 @@@ ++Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ ++Name: ceph ++Maintainer: Sage Weil ++Source: http://ceph.com/ ++Files-Excluded: debian ++ ++Files: * ++Copyright: 2004-2014 Sage Weil ++ 2004-2014 Inktank ++ Inktank, Inc ++ Inktank Storage, Inc. ++ 2012-2021 Red Hat ++ 2013-2014 Cloudwatt ++ 2013 CohortFS, LLC ++ 2004-2011 Dreamhost ++ 2013 eNovance SAS ++ 2014 Adam Crume ++ 2012 Florian Haas, hastexo ++ 2010 Greg Farnum ++ 2014 John Spray ++ 2011 Stanislav Sedov ++ 2013-2014 UnitedStack ++ 2011 Wido den Hollander ++ 2004-2021, The Ceph Project Developers ++ 2008-2011, New Dream Network ++ 2019-2021, SUSE LINUX GmbH ++ 2004-2006, Intel Corporation ++ 2011-2014, Stanford University ++ 2017 OVH ++ 2016 Allen Samuels ++ 2014 UnitedStack ++ 2015 XSky ++ 2017 International Business Machines Corp. ++ 2015 CohortFS, LLC. ++ 2015-2016 Mirantis, Inc. ++ 2011-2015 Edward Diener ++ 2014 FUJITSU LIMITED ++ 2012 Eleanor Cawthon ++ 2011-2018, Facebook, Inc. ++ 2011 The LevelDB Authors. ++ 2016 Mehdi Abaakouk ++ 2011 Josh Durgin ++ 2011 Hannu Valtonen ++ 2015 Hector Martin ++License: LGPL2.1 (see COPYING-LGPL2.1) ++ ++Files: src/fmt/* ++ src/googletest/* ++ src/isa-l/* ++Copyright: (c) 2012-2018, Victor Zverovich ++ (c) 2019, Paul Dreik ++ (c) 2018, Remotion (Igor Schulz) ++ (c) 2007-2013, Google Inc. ++ (c) 2007, Neal Norwitz ++ 2011-2017 Intel Corporation ++License: BSD 3-clause ++ ++Files: src/jaegertracing/thrift/* ++Copyright: (c) 2006-2019, The Apache Software Foundation ++ (c) 2009,2010 Dustin J. Mitchell ++ (c) 2009,2010 Zmanda Inc. ++ (c) 2009 David Reiss ++ (c) 2015 Jens Geyer ++ (c) 2008 Benjamin Kosnik ++ (c) 2012 Zack Weinberg ++ (c) 2013 Roy Stogner ++ (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov ++ (c) 2015 Paul Norman ++ (c) 2015 Moritz Klammler ++ (c) 2016, 2018 Krzesimir Nowak ++ (c) 2011 David Nadlinger ++License: Apache-2.0 ++ ++Files: src/jaegertracing/jaeger-client-cpp/* ++Copyright: (c) 2017 Uber Technologies, Inc. ++ (c) 2019, The Jaeger Authors ++ (c) 2004, 2006 The Linux Foundation and its contributors. ++ (c) 2012, Twitter Inc. ++License: Apache-2.0 ++ ++Files: src/jaegertracing/opentracing-cpp/3rd_party/include/opentracing/expected/* ++Copyright: (C) 2016 Martin Moene. ++ (c) 2002-2003 Eric Friedman, Itay Maman ++ (c) 2015 Microsoft Corporation ++License: Expat ++ ++Files: src/jaegertracing/opentracing-cpp/3rd_party/include/opentracing/variant/* ++ src/jaegertracing/opentracing-cpp/3rd_party/include/catch2/* ++Copyright: (c) MapBox ++License: BSD 3-clause ++ ++Files: src/java/* ++Copyright: Ceph authors ++License: Expat ++ ++Files: src/json_spirit/* ++Copyright: 2007-2011, John W. Wilkinson ++License: BSL-1.0 ++ ++Files: src/libkmip ++Copyright: (c) 2018-2019, The Johns Hopkins University/Applied Physics Laboratory ++License: Apache-2.0 ++ ++Files: src/liburing ++Copyright: (c) 2019 Jens Axboe ++ (c) 2019 Christoph Hellwig ++License: LGPL2.1 or later ++ ++Files: src/rapidjson ++Copyright: (c) 2006-2013 Alexander Chemeris ++ (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip ++License: BSD 3-clause ++ ++Files: src/rocksdb/* ++Copyright: Google Inc. ++ (c) 2011-present, Facebook, Inc. ++License: GPL-2 ++ ++Files: src/spawn/* ++Copyright: (c) 2006-2019 Google Inc. ++License: BSL-1.0 ++ ++Files: src/spdk/* ++Copyright: (c) Intel Corporation. ++License: BSD 3 clause ++ ++Files: src/xxHash/* ++Copyright: (c) 2012-2014, Yann Collet ++License: BSD 3-clause ++ ++Files: src/zstd/* ++Copyright: (c) 2016, Facebook, Inc. All rights reserved. ++License: BSD 3-clause ++ ++Files: src/seastar/* ++Copyright: (C) 2016-2020, ScyllaDB ++ (c) 2017-2019, Red Hat, Inc. ++ (c) 2014-2020, Cloudius Systems, Ltd. ++ (c) 2010-2018, Intel Corporation ++ (c) 2003-2013, Christopher M. Kohlhoff ++ (c) 2012-2018, 6WIND S.A. ++ (c) 2018, Luca Boccassi ++ (c) 2010, David Malone ++ (c) 2019, Elazar Leibovich ++ (c) 2013, Prometheus Team ++ (c) 2017-2018, Marvell International Ltd. ++ (c) 2014-2017, IBM Corporation ++ (c) 2015-2018, RehiveTech ++ (c) 2015-2018, CESNET ++ (c) 2015-2018, Cavium, Inc ++ (c) 2016-2018, NXP ++ (c) 2000-2018, Kitware, Inc. and Contributors ++ (c) 2017, Marek Waszkiewicz ++ (C) 2019, Lightbits Labs Ltd. ++ (c) 2016, Canonical Limited. ++ (c) 2019, Netcope Technologies, a.s. ++ (c) 2015-2018, Atomic Rules LLC ++ (c) 2015-2016, QLogic Corporation ++ (c) 2017-2018, Semihalf. ++ (c) 2013-2018, Broadcom ++ (c) 2008-2018, Cisco Systems, Inc. ++ (c) 2014-2016, Freescale Semiconductor, Inc. ++ (c) 2013-2017, Wind River Systems, Inc. ++ (c) 2015-2018, Mellanox Technologies, Ltd ++ (c) 2018-2019, Arm Limited ++ (c) 2019, Cesnet ++ (c) 2014-2018, Chelsio Communications. ++ (c) 2018, Aquantia Corporation ++ (c) 2018, Microsoft Corporation. ++ (c) 2018, The DPDK contributors ++ (c) 2017-2018, Solarflare Communications Inc. ++ (c) 2015-2016, Amazon.com, Inc. ++ (c) 2014-2018, Netronome Systems, Inc. ++ (c) 2016, IGEL Co., Ltd. ++ (c) 2018, Advanced Micro Devices, Inc. ++ (c) 2018, ARM Corporation. ++ (c) 2014-2017, aQuantia Corporation. ++ (c) 2018, Synopsys, Inc. All rights reserved. ++ (c) 2007, Nuova Systems, Inc. All rights reserved. ++ (c) 2013-2015, Brocade Communications Systems, Inc. ++ (c) 2012, NetApp Inc. ++ (c) 2010, Jonathan Armani ++ (c) 2010, Fabien Romano ++ (c) 2010, Michael Knudsen ++License: Apache-2.0 ++Comment: ++ The dpdk folder is under various folders: ++ bsd-3-clause, gpl-2.0 and lgpl-2.1. ++ ++Files: src/common/crc32c_intel_baseline.c ++Copyright: 2012-2013 Intel Corporation ++License: BSD 3-clause ++ ++Files: src/crimson/common/layout.h ++Copyright: 2018 The Abseil Authors ++License: Apache-2.0 ++ ++Files: cmake/modules/FindPython3.cmake cmake/modules/FindBacktrace.cmake ++ cmake/modules/FindBoost.cmake cmake/modules/FindPython/Support.cmake ++Copyright: (c) 2013 Vadim Zhukov ++License: BSD 3-clause ++ ++Files: cmake/modules/Findblkid.cmake ++Copyright: (c) 2007-2012 Hypertable, Inc. ++License: GPL-3+ ++ ++Files: cmake/modules/FindLTTngUST.cmake ++Copyright: ++ Copyright 2016 Kitware, Inc. ++ Copyright 2016 Philippe Proulx ++License: BSD 3-clause ++ ++Files: make-debs.sh ++Copyright: (c) Loic Dachary ++ (c) 2015 Red Hat ++License: GPL-2+ ++ ++Files: fusetrace/fusetrace_ll.cc ++Copyright: (C) 2001-2007 Miklos Szeredi ++License: GPL-2 ++ ++Files: doc/* ++Copyright: (c) 2010-2012 New Dream Network and contributors ++License: Creative Commons Attribution Share Alike 3.0 (CC-BY-SA-3.0) ++ ++Files: src/boost/* ++Copyright: Boost project contributors ++License: BSL-1.0 ++Comment: ++ Ceph embedds boost sources, which has complex copyright. Rather than ++ duplicating its debian copyright, this package relies on the package ++ maintainer of Boost for this work. ++ . ++ Please see /usr/share/doc/libboost*/copyright fore more details. ++ ++Files: bin/git-archive-all.sh ++License: GPL3 ++ ++Files: src/mount/canonicalize.c ++Copyright: Copyright (C) 1993 Rick Sladkey ++License: LGPL2 or later (see COPYING-GPL2) ++ ++ ++Files: src/os/btrfs_ioctl.h ++Copyright: Copyright (C) 2007 Oracle. All rights reserved. ++License: GPL2 (see COPYING-GPL2) ++ ++Files: src/include/ceph_hash.cc ++Copyright: None ++License: Public domain ++ ++Files: src/common/bloom_filter.hpp ++Copyright: Copyright (C) 2000 Arash Partow ++License: BSL-1.0 ++ ++Files: src/common/crc32c_intel*: ++Copyright: ++ Copyright 2012-2013 Intel Corporation All Rights Reserved. ++License: BSD 3-clause ++ ++Files: src/common/sctp_crc32.c: ++Copyright: ++ Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. ++ Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved ++License: ++ Redistribution and use in source and binary forms, with or without ++ modification, are permitted provided that the following conditions are met: ++ . ++ a) Redistributions of source code must retain the above copyright notice, ++ this list of conditions and the following disclaimer. ++ . ++ b) Redistributions in binary form must reproduce the above copyright ++ notice, this list of conditions and the following disclaimer in ++ the documentation and/or other materials provided with the distribution. ++ . ++ c) Neither the name of Cisco Systems, Inc. nor the names of its ++ contributors may be used to endorse or promote products derived ++ from this software without specific prior written permission. ++ . ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE ++ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ THE POSSIBILITY OF SUCH DAMAGE. ++ ++Files: src/json_spirit ++Copyright: ++ Copyright John W. Wilkinson 2007 - 2011 ++License: ++ The MIT License ++ ++ Copyright (c) 2007 - 2010 John W. Wilkinson ++ ++ Permission is hereby granted, free of charge, to any person ++ obtaining a copy of this software and associated documentation ++ files (the "Software"), to deal in the Software without ++ restriction, including without limitation the rights to use, ++ copy, modify, merge, publish, distribute, sublicense, and/or sell ++ copies of the Software, and to permit persons to whom the ++ Software is furnished to do so, subject to the following ++ conditions: ++ ++ The above copyright notice and this permission notice shall be ++ included in all copies or substantial portions of the Software. ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ++ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ++ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ OTHER DEALINGS IN THE SOFTWARE. ++ ++Files: src/test/common/Throttle.cc src/test/filestore/chain_xattr.cc ++Copyright: Copyright (C) 2013 Cloudwatt ++License: LGPL2.1 or later ++ ++Files: src/osd/ErasureCodePluginJerasure/*.{c,h} ++Copyright: Copyright (c) 2011, James S. Plank ++License: ++ Redistribution and use in source and binary forms, with or without ++ modification, are permitted provided that the following conditions ++ are met: ++ ++ - Redistributions of source code must retain the above copyright ++ notice, this list of conditions and the following disclaimer. ++ ++ - Redistributions in binary form must reproduce the above copyright ++ notice, this list of conditions and the following disclaimer in ++ the documentation and/or other materials provided with the ++ distribution. ++ ++ - Neither the name of the University of Tennessee nor the names of its ++ contributors may be used to endorse or promote products derived ++ from this software without specific prior written permission. ++ ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ++ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, ++ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS ++ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED ++ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY ++ WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ POSSIBILITY OF SUCH DAMAGE. ++ ++ ++Files: qa/workunits/erasure-code/jquery.js ++Copyright: 2012 jQuery Foundation and other contributors ++License: MIT ++ ++Files: qa/workunits/erasure-code/jquery.{flot.categories,flot}.js ++Copyright: 2007-2014 IOLA and Ole Laursen. ++License: MIT ++ ++Files: src/include/timegm.h ++Copyright: Howard Hinnant ++ 2010-2011 Vicente J. Botet Escriba ++License: BSL-1.0 ++ ++Files: src/pybind/mgr/diskprediction_local/models/* ++Copyright: None ++License: Public domain ++ ++Files: src/ceph-volume/plugin/zfs/* ++Copyright: 2018, Willem Jan Withagen ++License: BSD 3-clause ++ ++Files: src/test/perf_local.cc ++Copyright: ++ (c) 2011-2014 Stanford University ++ (c) 2011 Facebook ++License: ++ The MIT License ++ ++ ++Comment: ----------------------------------------------- ++ Content above is taken from upstream's COPYING file. ++ Unfortunately it is incomplete. Debian/Ubuntu packaging ++ findings/additions are below. ++ ------------------------------------------------------- ++ ++ ++Files: src/erasure-code/jerasure/ErasureCode* ++ src/erasure-code/ErasureCode* ++ src/erasure-code/isa/* ++ src/include/str_map.h ++ src/test/common/test_str_map.cc ++ src/test/erasure-code/* ++ src/test/rgw/test_rgw_manifest.cc ++Copyright: 2014 CERN/Switzerland ++ 2013-2014 Cloudwatt ++ 2014 Red Hat ++ 2013 eNovance SAS ++License: LGPL-2.1+ ++ ++ ++Files: src/erasure-code/isa/isa-l/erasure_code/* ++Copyright: 2011-2014 Intel Corporation ++License: BSD-3-clause ++ ++Files: src/rocksdb/* ++Copyright: 2004-2013 Facebook, Inc. ++ 2011 The LevelDB Authors ++ 2009 Google Inc. ++License: BSD-3-clause ++Comment: ++ Additional Grant of Patent Rights ++ . ++ “Software” means the rocksdb software distributed by Facebook, Inc. ++ . ++ Facebook hereby grants you a perpetual, worldwide, royalty-free, ++ non-exclusive, irrevocable (subject to the termination provision below) ++ license under any rights in any patent claims owned by Facebook, to make, ++ have made, use, sell, offer to sell, import, and otherwise transfer the ++ Software. For avoidance of doubt, no license is granted under Facebook’s ++ rights in any patent claims that are infringed by (i) modifications to the ++ Software made by you or a third party, or (ii) the Software in combination ++ with any software or other technology provided by you or a third party. ++ . ++ The license granted hereunder will terminate, automatically and without ++ notice, for anyone that makes any claim (including by filing any lawsuit, ++ assertion or other action) alleging (a) direct, indirect, or contributory ++ infringement or inducement to infringe any patent: (i) by Facebook or any ++ of its subsidiaries or affiliates, whether or not such claim is related ++ to the Software, (ii) by any party if such claim arises in whole or in ++ part from any software, product or service of Facebook or any of its ++ subsidiaries or affiliates, whether or not such claim is related to the ++ Software, or (iii) by any party relating to the Software; or (b) that ++ any right in any patent claim of Facebook is invalid or unenforceable. ++ ++ ++Files: src/rocksdb/util/xxhash.* ++Copyright: 2012-2014, Yann Collet. ++License: BSD-2-clause ++ Redistribution and use in source and binary forms, with or without ++ modification, are permitted provided that the following conditions are ++ met: ++ . ++ * Redistributions of source code must retain the above copyright ++ notice, this list of conditions and the following disclaimer. ++ * Redistributions in binary form must reproduce the above ++ copyright notice, this list of conditions and the following disclaimer ++ in the documentation and/or other materials provided with the ++ distribution. ++ . ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++Files: src/mount/canonicalize.c ++ src/test/common/test_config.cc ++ src/test/crush/TestCrushWrapper.cc ++ src/test/common/Throttle.cc ++ src/test/objectstore/chain_xattr.cc ++ src/test/mon/mon-test-helpers.sh ++ src/test/objectstore/chain_xattr.cc ++ src/test/osd/osd-test-helpers.sh ++ src/ceph-disk ++ src/stop.sh ++Copyright: 1993 Rick Sladkey ++ 2013 Inktank ++ 2013-2014 Cloudwatt ++License: LGPL-2+ ++ ++Files: src/os/btrfs_ioctl.h ++ src/test/mon/PGMap.cc ++Copyright: 2007 Oracle. All rights reserved. ++ 2014 Inktank ++License: GPL-2 ++ ++Files: src/common/ceph_hash.cc ++Copyright: 1995-1997 Robert J. Jenkins Jr. ++License: public-domain ++ This file uses Robert Jenkin's hash function as detailed at: ++ . ++ http://burtleburtle.net/bob/hash/evahash.html ++ . ++ This is in the public domain. ++ ++Files: src/common/bloom_filter.hpp ++Copyright: 2000 Arash Partow ++License: BSL-1.0 ++ ++Files: src/common/crc32c_intel* ++Copyright: 2012-2013 Intel Corporation All Rights Reserved. ++License: BSD-3-clause ++ ++Files: src/common/sctp_crc32.c ++Copyright: 2001-2007, by Cisco Systems, Inc. All rights reserved, ++ 2004-2006 Intel Corporation - All Rights Reserved ++License: BSD-3-clause ++ ++Files: src/erasure-code/jerasure/gf-complete/*/* ++Copyright: 2013 James S. Plank ++ Ethan L. Miller ++ Kevin M. Greenan ++ Benjamin A. Arnold ++ John A. Burnum ++ Adam W. Disney ++ Allen C. McBride ++License: BSD-3-clause ++Comment: ++ https://bitbucket.org/jimplank/gf-complete ++ ++Files: src/erasure-code/jerasure/jerasure/*/* ++Copyright: 2011-2013 James S. Plank ++ 2013 Kevin Greenan ++License: BSD-3-clause ++ ++Files: src/gtest/* ++Copyright: 2008, Google Inc. ++License: BSD-3-clause ++ ++Files: src/civetweb/* ++Copyright: 2004-2013 Sergey Lyubka ++ 2013-2014 the Civetweb developers ++License: Expat ++ ++Files: src/json_spirit/* ++Copyright: 2007-2011, John W. Wilkinson ++License: Expat ++ ++Files: src/java/native/ScopedLocalRef.h ++ src/java/native/JniConstants.* ++Copyright: 2010 The Android Open Source Project ++License: Apache-2.0 ++ ++Files: src/libs3/* ++Copyright: 2008 Bryan Ischo ++License: GPL-3/OpenSSL ++ libs3 is free software: you can redistribute it and/or modify it under the ++ terms of the GNU General Public License as published by the Free Software ++ Foundation, version 3 of the License. ++ . ++ In addition, as a special exception, the copyright holders give ++ permission to link the code of this library and its programs with the ++ OpenSSL library, and distribute linked combinations including the two. ++ . ++ libs3 is distributed in the hope that it will be useful, but WITHOUT ANY ++ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ++ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ++ details. ++ . ++ The complete text of the GNU General Public License version 3 ++ can be found in "/usr/share/common-licenses/GPL-3' file. ++ ++ ++Files: src/mount/mtab.c ++Copyright: util-linux-ng AUTHORS ++License: GPL-2+ ++Comment: ++ "mount/fstab.c" from line 559: ++ https://git.kernel.org/cgit/utils/util-linux/util-linux.git/tree/mount-deprecated/fstab.c?h=v2.22#n559 ++ https://git.kernel.org/cgit/utils/util-linux/util-linux.git/tree/README.licensing ++ ++Files: src/test/librbd/fsx.c ++Copyright: 1991, NeXT Computer, Inc. ++License: APSL-2.0 ++ The contents of this file constitute Original Code as defined in and ++ are subject to the Apple Public Source License Version 2.0 (the ++ "License"). You may not use this file except in compliance with the ++ License. Please obtain a copy of the License at ++ http://www.opensource.apple.com/apsl/ and read it before using this file. ++ . ++ This Original Code and all software distributed under the License are ++ distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ++ EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ++ INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ++ License for the specific language governing rights and limitations ++ under the License. ++Comment: ++ http://codemonkey.org.uk/projects/fsx/ ++ http://codemonkey.org.uk/projects/fsx/fsx-macosforge/fsx.c ++ ++Files: man/* ++ debian/man/* ++Copyright: 2010-2014, Inktank Storage, Inc. and contributors. ++License: CC-BY-SA-3.0 ++ ++Files: debian/missing-sources/bootstrap.js ++Copyright: 2011-2015 Twitter, Inc ++License: MIT ++ ++Files: debian/missing-sources/two.js ++Copyright: 2012 - 2017 jonobr1 / http://jonobr1.com ++License: MIT ++ ++Files: debian/* ++Copyright: 2010 Sage Weil ++ 2010 Canonical, Ltd. ++ 2011-2013 László Böszörményi (GCS) ++ 2013-2014 James Page ++ 2014 Dmitry Smirnov ++ 2019 Bernd Zeimetz ++License: LGPL-2.1 ++ ++License: Expat ++ Permission is hereby granted, free of charge, to any person or organization ++ obtaining a copy of the software and accompanying documentation covered by ++ this license (the "Software") to use, reproduce, display, distribute, ++ execute, and transmit the Software, and to prepare derivative works of the ++ Software, and to permit third-parties to whom the Software is furnished to ++ do so, all subject to the following: ++ . ++ The copyright notices in the Software and this entire statement, ++ including the above license grant, this restriction and the following ++ disclaimer, must be included in all copies of the Software, in whole or ++ in part, and all derivative works of the Software, unless such copies ++ or derivative works are solely in the form of machine-executable object ++ code generated by a source language processor. ++ . ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT ++ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE ++ FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ++ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ DEALINGS IN THE SOFTWARE. ++ ++License: Apache-2.0 ++ Licensed under the Apache License, Version 2.0 (the "License"); ++ you may not use this file except in compliance with the License. ++ You may obtain a copy of the License at ++ . ++ http://www.apache.org/licenses/LICENSE-2.0 ++ . ++ Unless required by applicable law or agreed to in writing, software ++ distributed under the License is distributed on an "AS IS" BASIS, ++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ See the License for the specific language governing permissions and ++ limitations under the License. ++ . ++ The complete text of the Apache License, Version 2.0 ++ can be found in "/usr/share/common-licenses/Apache-2.0". ++ ++ ++License: GPL-2 ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ . ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ . ++ You should have received a copy of the GNU General Public License along ++ with this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ . ++ On Debian systems, the complete text of the GNU General Public License ++ version 2 can be found in `/usr/share/common-licenses/GPL-2' file. ++ ++License: GPL-2+ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 2 of the License, or ++ (at your option) any later version. ++ . ++ This package is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ . ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ . ++ On Debian systems, the complete text of the GNU General Public License ++ version 2 can be found in `/usr/share/common-licenses/GPL-2'. ++ ++License: GPL-3+ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ . ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ . ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ . ++ On Debian systems, the complete text of the GNU General Public ++ License version 3 can be found in `/usr/share/common-licenses/GPL-3'. ++ ++License: LGPL-2.1 ++ This library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License version 2.1 as published by the Free Software Foundation. ++ . ++ This library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ . ++ You should have received a copy of the GNU Lesser General Public ++ License along with this library; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ . ++ On Debian systems, the complete text of the GNU Lesser General ++ Public License can be found in `/usr/share/common-licenses/LGPL-2.1'. ++ ++License: LGPL-2.1+ ++ This library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ . ++ This library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ . ++ You should have received a copy of the GNU Lesser General Public ++ License along with this library; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ . ++ On Debian systems, the complete text of the GNU Lesser General ++ Public License can be found in `/usr/share/common-licenses/LGPL-2.1'. ++ ++License: LGPL-2+ ++ This library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License version 2 (or later) as published by the Free Software Foundation. ++ . ++ This library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ . ++ You should have received a copy of the GNU Lesser General Public ++ License along with this library; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ . ++ On Debian systems, the complete text of the GNU Lesser General ++ Public License 2 can be found in `/usr/share/common-licenses/LGPL-2'. ++ ++License: Expat ++ Permission is hereby granted, free of charge, to any person obtaining a copy ++ of this software and associated documentation files (the "Software"), to deal ++ in the Software without restriction, including without limitation the rights ++ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ copies of the Software, and to permit persons to whom the Software is ++ furnished to do so, subject to the following conditions: ++ . ++ The above copyright notice and this permission notice shall be included in ++ all copies or substantial portions of the Software. ++ . ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ THE SOFTWARE. ++Comment: ++ This license also known as "MIT" however FSF consider "MIT" labelling ++ ambiguous and copyright-format specification recommend to label such license ++ as "Expat". ++ ++License: CC-BY-SA-3.0 ++ Creative Commons Attribution-ShareAlike 3.0 Unported ++ ․ ++ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE ++ LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ++ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ++ ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE ++ INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ++ ITS USE. ++ ․ ++ License ++ ․ ++ THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE ++ COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY ++ COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS ++ AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. ++ ․ ++ BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE ++ TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY ++ BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS ++ CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND ++ CONDITIONS. ++ ․ ++ 1. Definitions ++ ․ ++ a. "Adaptation" means a work based upon the Work, or upon the Work and ++ other pre-existing works, such as a translation, adaptation, derivative ++ work, arrangement of music or other alterations of a literary or ++ artistic work, or phonogram or performance and includes cinematographic ++ adaptations or any other form in which the Work may be recast, ++ transformed, or adapted including in any form recognizably derived from ++ the original, except that a work that constitutes a Collection will not ++ be considered an Adaptation for the purpose of this License. For the ++ avoidance of doubt, where the Work is a musical work, performance or ++ phonogram, the synchronization of the Work in timed-relation with a ++ moving image ("synching") will be considered an Adaptation for the ++ purpose of this License. ++ ․ ++ b. "Collection" means a collection of literary or artistic works, such ++ as encyclopedias and anthologies, or performances, phonograms or ++ broadcasts, or other works or subject matter other than works listed in ++ Section 1(f) below, which, by reason of the selection and arrangement of ++ their contents, constitute intellectual creations, in which the Work is ++ included in its entirety in unmodified form along with one or more other ++ contributions, each constituting separate and independent works in ++ themselves, which together are assembled into a collective whole. A work ++ that constitutes a Collection will not be considered an Adaptation (as ++ defined below) for the purposes of this License. ++ ․ ++ c. "Creative Commons Compatible License" means a license that is listed ++ at http://creativecommons.org/compatiblelicenses that has been approved ++ by Creative Commons as being essentially equivalent to this License, ++ including, at a minimum, because that license: (i) contains terms that ++ have the same purpose, meaning and effect as the License Elements of ++ this License; and, (ii) explicitly permits the relicensing of ++ adaptations of works made available under that license under this ++ License or a Creative Commons jurisdiction license with the same License ++ Elements as this License. ++ ․ ++ d. "Distribute" means to make available to the public the original and ++ copies of the Work or Adaptation, as appropriate, through sale or other ++ transfer of ownership. ++ ․ ++ e. "License Elements" means the following high-level license attributes ++ as selected by Licensor and indicated in the title of this License: ++ Attribution, ShareAlike. ++ ․ ++ f. "Licensor" means the individual, individuals, entity or entities that ++ offer(s) the Work under the terms of this License. ++ ․ ++ g. "Original Author" means, in the case of a literary or artistic work, ++ the individual, individuals, entity or entities who created the Work or ++ if no individual or entity can be identified, the publisher; and in ++ addition (i) in the case of a performance the actors, singers, ++ musicians, dancers, and other persons who act, sing, deliver, declaim, ++ play in, interpret or otherwise perform literary or artistic works or ++ expressions of folklore; (ii) in the case of a phonogram the producer ++ being the person or legal entity who first fixes the sounds of a ++ performance or other sounds; and, (iii) in the case of broadcasts, the ++ organization that transmits the broadcast. ++ ․ ++ h. "Work" means the literary and/or artistic work offered under the ++ terms of this License including without limitation any production in the ++ literary, scientific and artistic domain, whatever may be the mode or ++ form of its expression including digital form, such as a book, pamphlet ++ and other writing; a lecture, address, sermon or other work of the same ++ nature; a dramatic or dramatico-musical work; a choreographic work or ++ entertainment in dumb show; a musical composition with or without words; ++ a cinematographic work to which are assimilated works expressed by a ++ process analogous to cinematography; a work of drawing, painting, ++ architecture, sculpture, engraving or lithography; a photographic work ++ to which are assimilated works expressed by a process analogous to ++ photography; a work of applied art; an illustration, map, plan, sketch ++ or three-dimensional work relative to geography, topography, ++ architecture or science; a performance; a broadcast; a phonogram; a ++ compilation of data to the extent it is protected as a copyrightable ++ work; or a work performed by a variety or circus performer to the extent ++ it is not otherwise considered a literary or artistic work. ++ ․ ++ i. "You" means an individual or entity exercising rights under this ++ License who has not previously violated the terms of this License with ++ respect to the Work, or who has received express permission from the ++ Licensor to exercise rights under this License despite a previous ++ violation. ++ ․ ++ j. "Publicly Perform" means to perform public recitations of the Work ++ and to communicate to the public those public recitations, by any means ++ or process, including by wire or wireless means or public digital ++ performances; to make available to the public Works in such a way that ++ members of the public may access these Works from a place and at a place ++ individually chosen by them; to perform the Work to the public by any ++ means or process and the communication to the public of the performances ++ of the Work, including by public digital performance; to broadcast and ++ rebroadcast the Work by any means including signs, sounds or images. ++ ․ ++ k. "Reproduce" means to make copies of the Work by any means including ++ without limitation by sound or visual recordings and the right of ++ fixation and reproducing fixations of the Work, including storage of a ++ protected performance or phonogram in digital form or other electronic ++ medium. ++ ․ ++ 2. Fair Dealing Rights. Nothing in this License is intended to reduce, ++ limit, or restrict any uses free from copyright or rights arising from ++ limitations or exceptions that are provided for in connection with the ++ copyright protection under copyright law or other applicable laws. ++ ․ ++ 3. License Grant. Subject to the terms and conditions of this License, ++ Licensor hereby grants You a worldwide, royalty-free, non-exclusive, ++ perpetual (for the duration of the applicable copyright) license to ++ exercise the rights in the Work as stated below: ++ ․ ++ a. to Reproduce the Work, to incorporate the Work into one or more ++ Collections, and to Reproduce the Work as incorporated in the ++ Collections; ++ ․ ++ b. to create and Reproduce Adaptations provided that any such ++ Adaptation, including any translation in any medium, takes reasonable ++ steps to clearly label, demarcate or otherwise identify that changes ++ were made to the original Work. For example, a translation could be ++ marked "The original work was translated from English to Spanish," or a ++ modification could indicate "The original work has been modified."; ++ ․ ++ c. to Distribute and Publicly Perform the Work including as incorporated ++ in Collections; and, ++ ․ ++ d. to Distribute and Publicly Perform Adaptations. ++ ․ ++ e. For the avoidance of doubt: ++ ․ ++ i. Non-waivable Compulsory License Schemes. In those jurisdictions in ++ which the right to collect royalties through any statutory or compulsory ++ licensing scheme cannot be waived, the Licensor reserves the exclusive ++ right to collect such royalties for any exercise by You of the rights ++ granted under this License; ++ ․ ++ ii. Waivable Compulsory License Schemes. In those jurisdictions in which ++ the right to collect royalties through any statutory or compulsory ++ licensing scheme can be waived, the Licensor waives the exclusive right ++ to collect such royalties for any exercise by You of the rights granted ++ under this License; and, ++ ․ ++ iii. Voluntary License Schemes. The Licensor waives the right to collect ++ royalties, whether individually or, in the event that the Licensor is a ++ member of a collecting society that administers voluntary licensing ++ schemes, via that society, from any exercise by You of the rights ++ granted under this License. ++ ․ ++ The above rights may be exercised in all media and formats whether now ++ known or hereafter devised. The above rights include the right to make ++ such modifications as are technically necessary to exercise the rights ++ in other media and formats. Subject to Section 8(f), all rights not ++ expressly granted by Licensor are hereby reserved. ++ ․ ++ 4. Restrictions. The license granted in Section 3 above is expressly ++ made subject to and limited by the following restrictions: ++ ․ ++ a. You may Distribute or Publicly Perform the Work only under the terms ++ of this License. You must include a copy of, or the Uniform Resource ++ Identifier (URI) for, this License with every copy of the Work You ++ Distribute or Publicly Perform. You may not offer or impose any terms on ++ the Work that restrict the terms of this License or the ability of the ++ recipient of the Work to exercise the rights granted to that recipient ++ under the terms of the License. You may not sublicense the Work. You ++ must keep intact all notices that refer to this License and to the ++ disclaimer of warranties with every copy of the Work You Distribute or ++ Publicly Perform. When You Distribute or Publicly Perform the Work, You ++ may not impose any effective technological measures on the Work that ++ restrict the ability of a recipient of the Work from You to exercise the ++ rights granted to that recipient under the terms of the License. This ++ Section 4(a) applies to the Work as incorporated in a Collection, but ++ this does not require the Collection apart from the Work itself to be ++ made subject to the terms of this License. If You create a Collection, ++ upon notice from any Licensor You must, to the extent practicable, ++ remove from the Collection any credit as required by Section 4(c), as ++ requested. If You create an Adaptation, upon notice from any Licensor ++ You must, to the extent practicable, remove from the Adaptation any ++ credit as required by Section 4(c), as requested. ++ ․ ++ b. You may Distribute or Publicly Perform an Adaptation only under the ++ terms of: (i) this License; (ii) a later version of this License with ++ the same License Elements as this License; (iii) a Creative Commons ++ jurisdiction license (either this or a later license version) that ++ contains the same License Elements as this License (e.g., ++ Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible ++ License. If you license the Adaptation under one of the licenses ++ mentioned in (iv), you must comply with the terms of that license. If ++ you license the Adaptation under the terms of any of the licenses ++ mentioned in (i), (ii) or (iii) (the "Applicable License"), you must ++ comply with the terms of the Applicable License generally and the ++ following provisions: (I) You must include a copy of, or the URI for, ++ the Applicable License with every copy of each Adaptation You Distribute ++ or Publicly Perform; (II) You may not offer or impose any terms on the ++ Adaptation that restrict the terms of the Applicable License or the ++ ability of the recipient of the Adaptation to exercise the rights ++ granted to that recipient under the terms of the Applicable License; ++ (III) You must keep intact all notices that refer to the Applicable ++ License and to the disclaimer of warranties with every copy of the Work ++ as included in the Adaptation You Distribute or Publicly Perform; (IV) ++ when You Distribute or Publicly Perform the Adaptation, You may not ++ impose any effective technological measures on the Adaptation that ++ restrict the ability of a recipient of the Adaptation from You to ++ exercise the rights granted to that recipient under the terms of the ++ Applicable License. This Section 4(b) applies to the Adaptation as ++ incorporated in a Collection, but this does not require the Collection ++ apart from the Adaptation itself to be made subject to the terms of the ++ Applicable License. ++ ․ ++ c. If You Distribute, or Publicly Perform the Work or any Adaptations or ++ Collections, You must, unless a request has been made pursuant to ++ Section 4(a), keep intact all copyright notices for the Work and ++ provide, reasonable to the medium or means You are utilizing: (i) the ++ name of the Original Author (or pseudonym, if applicable) if supplied, ++ and/or if the Original Author and/or Licensor designate another party or ++ parties (e.g., a sponsor institute, publishing entity, journal) for ++ attribution ("Attribution Parties") in Licensor's copyright notice, ++ terms of service or by other reasonable means, the name of such party or ++ parties; (ii) the title of the Work if supplied; (iii) to the extent ++ reasonably practicable, the URI, if any, that Licensor specifies to be ++ associated with the Work, unless such URI does not refer to the ++ copyright notice or licensing information for the Work; and (iv) , ++ consistent with Ssection 3(b), in the case of an Adaptation, a credit ++ identifying the use of the Work in the Adaptation (e.g., "French ++ translation of the Work by Original Author," or "Screenplay based on ++ original Work by Original Author"). The credit required by this Section ++ 4(c) may be implemented in any reasonable manner; provided, however, ++ that in the case of a Adaptation or Collection, at a minimum such credit ++ will appear, if a credit for all contributing authors of the Adaptation ++ or Collection appears, then as part of these credits and in a manner at ++ least as prominent as the credits for the other contributing authors. ++ For the avoidance of doubt, You may only use the credit required by this ++ Section for the purpose of attribution in the manner set out above and, ++ by exercising Your rights under this License, You may not implicitly or ++ explicitly assert or imply any connection with, sponsorship or ++ endorsement by the Original Author, Licensor and/or Attribution Parties, ++ as appropriate, of You or Your use of the Work, without the separate, ++ express prior written permission of the Original Author, Licensor and/or ++ Attribution Parties. ++ ․ ++ d. Except as otherwise agreed in writing by the Licensor or as may be ++ otherwise permitted by applicable law, if You Reproduce, Distribute or ++ Publicly Perform the Work either by itself or as part of any Adaptations ++ or Collections, You must not distort, mutilate, modify or take other ++ derogatory action in relation to the Work which would be prejudicial to ++ the Original Author's honor or reputation. Licensor agrees that in those ++ jurisdictions (e.g. Japan), in which any exercise of the right granted ++ in Section 3(b) of this License (the right to make Adaptations) would be ++ deemed to be a distortion, mutilation, modification or other derogatory ++ action prejudicial to the Original Author's honor and reputation, the ++ Licensor will waive or not assert, as appropriate, this Section, to the ++ fullest extent permitted by the applicable national law, to enable You ++ to reasonably exercise Your right under Section 3(b) of this License ++ (right to make Adaptations) but not otherwise. ++ ․ ++ 5. Representations, Warranties and Disclaimer ++ ․ ++ UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR ++ OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY ++ KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, ++ INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, ++ FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF ++ LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, ++ WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE ++ EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. ++ ․ ++ 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE ++ LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ++ ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ++ ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS ++ BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. ++ ․ ++ 7. Termination ++ ․ ++ a. This License and the rights granted hereunder will terminate ++ automatically upon any breach by You of the terms of this License. ++ Individuals or entities who have received Adaptations or Collections ++ from You under this License, however, will not have their licenses ++ terminated provided such individuals or entities remain in full ++ compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will ++ survive any termination of this License. ++ ․ ++ b. Subject to the above terms and conditions, the license granted here ++ is perpetual (for the duration of the applicable copyright in the Work). ++ Notwithstanding the above, Licensor reserves the right to release the ++ Work under different license terms or to stop distributing the Work at ++ any time; provided, however that any such election will not serve to ++ withdraw this License (or any other license that has been, or is ++ required to be, granted under the terms of this License), and this ++ License will continue in full force and effect unless terminated as ++ stated above. ++ ․ ++ 8. Miscellaneous ++ ․ ++ a. Each time You Distribute or Publicly Perform the Work or a ++ Collection, the Licensor offers to the recipient a license to the Work ++ on the same terms and conditions as the license granted to You under ++ this License. ++ ․ ++ b. Each time You Distribute or Publicly Perform an Adaptation, Licensor ++ offers to the recipient a license to the original Work on the same terms ++ and conditions as the license granted to You under this License. ++ ․ ++ c. If any provision of this License is invalid or unenforceable under ++ applicable law, it shall not affect the validity or enforceability of ++ the remainder of the terms of this License, and without further action ++ by the parties to this agreement, such provision shall be reformed to ++ the minimum extent necessary to make such provision valid and ++ enforceable. ++ ․ ++ d. No term or provision of this License shall be deemed waived and no ++ breach consented to unless such waiver or consent shall be in writing ++ and signed by the party to be charged with such waiver or consent. ++ ․ ++ e. This License constitutes the entire agreement between the parties ++ with respect to the Work licensed here. There are no understandings, ++ agreements or representations with respect to the Work not specified ++ here. Licensor shall not be bound by any additional provisions that may ++ appear in any communication from You. This License may not be modified ++ without the mutual written agreement of the Licensor and You. ++ ․ ++ f. The rights granted under, and the subject matter referenced, in this ++ License were drafted utilizing the terminology of the Berne Convention ++ for the Protection of Literary and Artistic Works (as amended on ++ September 28, 1979), the Rome Convention of 1961, the WIPO Copyright ++ Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and ++ the Universal Copyright Convention (as revised on July 24, 1971). These ++ rights and subject matter take effect in the relevant jurisdiction in ++ which the License terms are sought to be enforced according to the ++ corresponding provisions of the implementation of those treaty ++ provisions in the applicable national law. If the standard suite of ++ rights granted under applicable copyright law includes additional rights ++ not granted under this License, such additional rights are deemed to be ++ included in the License; this License is not intended to restrict the ++ license of any rights under applicable law. ++ ․ ++ ․ ++ Creative Commons Notice ++ ․ ++ Creative Commons is not a party to this License, and makes no warranty ++ whatsoever in connection with the Work. Creative Commons will not be ++ liable to You or any party on any legal theory for any damages ++ whatsoever, including without limitation any general, special, ++ incidental or consequential damages arising in connection to this ++ license. Notwithstanding the foregoing two (2) sentences, if Creative ++ Commons has expressly identified itself as the Licensor hereunder, it ++ shall have all rights and obligations of Licensor. ++ ․ ++ Except for the limited purpose of indicating to the public that the Work ++ is licensed under the CCPL, Creative Commons does not authorize the use ++ by either party of the trademark "Creative Commons" or any related ++ trademark or logo of Creative Commons without the prior written consent ++ of Creative Commons. Any permitted use will be in compliance with ++ Creative Commons' then-current trademark usage guidelines, as may be ++ published on its website or otherwise made available upon request from ++ time to time. For the avoidance of doubt, this trademark restriction ++ does not form part of the License. ++ ․ ++ Creative Commons may be contacted at http://creativecommons.org/. ++ ++License: BSD-3-clause ++ Redistribution and use in source and binary forms, with or without ++ modification, are permitted provided that the following conditions ++ are met: ++ . ++ 1. Redistributions of source code must retain the above ++ copyright notice, this list of conditions and the following ++ disclaimer. ++ . ++ 2. Redistributions in binary form must reproduce the above ++ copyright notice, this list of conditions and the following ++ disclaimer in the documentation and/or other materials ++ provided with the distribution. ++ . ++ 3. Neither the name of the copyright holder nor the names of ++ its contributors may be used to endorse or promote products ++ derived from this software without specific prior written ++ permission. ++ . ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ++ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ++ COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ++ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ OF THE POSSIBILITY OF SUCH DAMAGE. diff --cc debian/gbp.conf index 000000000,000000000..023aff39f new file mode 100644 --- /dev/null +++ b/debian/gbp.conf @@@ -1,0 -1,0 +1,3 @@@ ++[DEFAULT] ++debian-branch = debian/unstable ++pristine-tar = True diff --cc debian/lib-systemd/system-sleep/ceph index 000000000,000000000..cf62f8321 new file mode 100755 --- /dev/null +++ b/debian/lib-systemd/system-sleep/ceph @@@ -1,0 -1,0 +1,12 @@@ ++#!/bin/sh ++ ++#/lib/systemd/system-sleep/ceph ++ ++case $1 in ++pre) ++ /bin/systemctl stop ceph ++;; ++post) ++ /bin/systemctl start ceph ++;; ++esac diff --cc debian/lib-systemd/system/ceph-create-keys.service index 000000000,000000000..4e29bc1e9 new file mode 100644 --- /dev/null +++ b/debian/lib-systemd/system/ceph-create-keys.service @@@ -1,0 -1,0 +1,9 @@@ ++[Unit] ++Description=Create Ceph client.admin key when possible ++PartOf=ceph-mon.service ++ ++[Service] ++Environment=CLUSTER=ceph ++Environment=CONFIG=/etc/ceph/ceph.conf ++EnvironmentFile=-/etc/default/ceph ++ExecStart=/usr/sbin/ceph-create-keys --cluster ${CLUSTER} --id %H diff --cc debian/lib-systemd/system/ceph-mds.service index 000000000,000000000..86ff057f1 new file mode 100644 --- /dev/null +++ b/debian/lib-systemd/system/ceph-mds.service @@@ -1,0 -1,0 +1,16 @@@ ++[Unit] ++Description=Ceph metadata server daemon (MDS) ++Documentation=man:ceph-mds ++After=network-online.target nss-lookup.target ++Wants=network-online.target nss-lookup.target ++PartOf=ceph.target ++ ++[Service] ++LimitNOFILE=1048576 ++LimitNPROC=1048576 ++EnvironmentFile=-/etc/default/ceph ++Environment=CLUSTER=ceph ++ExecStart=/usr/bin/ceph-mds -f --cluster ${CLUSTER} --id %H --setuser ceph --setgroup ceph ++ ++[Install] ++WantedBy=multi-user.target diff --cc debian/lib-systemd/system/ceph-mon.service index 000000000,000000000..d89c74a64 new file mode 100644 --- /dev/null +++ b/debian/lib-systemd/system/ceph-mon.service @@@ -1,0 -1,0 +1,22 @@@ ++[Unit] ++Description=Ceph cluster monitor daemon ++Documentation=man:ceph-mon ++ ++After=network-online.target local-fs.target ceph-create-keys.service ++Wants=network-online.target local-fs.target ceph-create-keys.service ++ ++PartOf=ceph.target ++ ++[Service] ++LimitNOFILE=1048576 ++LimitNPROC=1048576 ++EnvironmentFile=-/etc/default/ceph ++Environment=CLUSTER=ceph ++ExecStart=/usr/bin/ceph-mon -f --cluster ${CLUSTER} --id %H --setuser ceph --setgroup ceph ++ExecReload=/bin/kill -HUP $MAINPID ++Restart=on-failure ++RestartSec=30 ++TasksMax=infinity ++ ++[Install] ++WantedBy=multi-user.target diff --cc debian/lib-systemd/system/ceph-osd@.service index 000000000,000000000..adfa6a02f new file mode 100644 --- /dev/null +++ b/debian/lib-systemd/system/ceph-osd@.service @@@ -1,0 -1,0 +1,22 @@@ ++[Unit] ++Description=Ceph object storage daemon (OSD) ++Documentation=man:ceph-osd ++After=network-online.target ++Wants=network-online.target ++PartOf=ceph.service ++RequiresMountsFor=/var/lib/ceph/osd/ceph-%i ++ ++[Service] ++Environment=CLUSTER=ceph ++Environment=CONFIG=/etc/ceph/ceph.conf ++EnvironmentFile=-/etc/default/ceph ++ExecStartPre=-/bin/sh -c '${osd_prestart_sh}' -- %i ++ExecStartPre=/usr/lib/ceph/ceph-osd-prestart.sh --id %i --cluster ${CLUSTER} ++ExecStart=/usr/bin/ceph-osd --id %i --foreground --cluster ${CLUSTER} -c ${CONFIG} ++ExecStopPost=-/bin/sh -c '${osd_poststop_sh}' -- %i ++LimitNOFILE=327680 ++Restart=on-failure ++RestartSec=30 ++ ++[Install] ++WantedBy=multi-user.target diff --cc debian/libcephfs-dev.install index 000000000,000000000..a23c5b057 new file mode 100644 --- /dev/null +++ b/debian/libcephfs-dev.install @@@ -1,0 -1,0 +1,2 @@@ ++usr/include/cephfs/*.h ++usr/lib/*/libcephfs.so diff --cc debian/libcephfs-java.jlibs index 000000000,000000000..1029fb53d new file mode 100644 --- /dev/null +++ b/debian/libcephfs-java.jlibs @@@ -1,0 -1,0 +1,1 @@@ ++debian/tmp/usr/share/java/libcephfs.jar diff --cc debian/libcephfs-jni.install index 000000000,000000000..15cb91d90 new file mode 100644 --- /dev/null +++ b/debian/libcephfs-jni.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/lib/*/libcephfs_jni.so* usr/lib/jni diff --cc debian/libcephfs-jni.lintian-overrides index 000000000,000000000..93a0dacaf new file mode 100644 --- /dev/null +++ b/debian/libcephfs-jni.lintian-overrides @@@ -1,0 -1,0 +1,1 @@@ ++binary-or-shlib-defines-rpath usr/lib/jni/* diff --cc debian/libcephfs2.install index 000000000,000000000..f09e93ca5 new file mode 100644 --- /dev/null +++ b/debian/libcephfs2.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/lib/*/libcephfs.so.* diff --cc debian/libcephfs2.lintian-overrides index 000000000,000000000..d4041ca8e new file mode 100644 --- /dev/null +++ b/debian/libcephfs2.lintian-overrides @@@ -1,0 -1,0 +1,2 @@@ ++# False-positives: ++spelling-error-in-binary * tEH the diff --cc debian/libcephfs2.symbols index 000000000,000000000..1e5a14a8d new file mode 100644 --- /dev/null +++ b/debian/libcephfs2.symbols @@@ -1,0 -1,0 +1,212 @@@ ++libcephfs.so.2 libcephfs2 #MINVER# ++ (regex|c++)"^_.*" 12.0.3 ++ _ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJZ17make_named_threadIZN4ceph5async15io_context_pool5startEsEUlvE_JEES_St17basic_string_viewIcSt11char_traitsIcEEOT_DpOT0_EUlSD_SG_E_S7_EEEEE6_M_runEv@Base 16.2.6+ds ++ _ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJZ17make_named_threadIZN4ceph5async15io_context_pool5startEsEUlvE_JEES_St17basic_string_viewIcSt11char_traitsIcEEOT_DpOT0_EUlSD_SG_E_S7_EEEEED0Ev@Base 16.2.6+ds ++ _ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJZ17make_named_threadIZN4ceph5async15io_context_pool5startEsEUlvE_JEES_St17basic_string_viewIcSt11char_traitsIcEEOT_DpOT0_EUlSD_SG_E_S7_EEEEED1Ev@Base 16.2.6+ds ++ _ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJZ17make_named_threadIZN4ceph5async15io_context_pool5startEsEUlvE_JEES_St17basic_string_viewIcSt11char_traitsIcEEOT_DpOT0_EUlSD_SG_E_S7_EEEEED2Ev@Base 16.2.6+ds ++ _ZTINSt6thread11_State_implINS_8_InvokerISt5tupleIJZ17make_named_threadIZN4ceph5async15io_context_pool5startEsEUlvE_JEES_St17basic_string_viewIcSt11char_traitsIcEEOT_DpOT0_EUlSD_SG_E_S7_EEEEEE@Base 16.2.6+ds ++ _ZTSNSt6thread11_State_implINS_8_InvokerISt5tupleIJZ17make_named_threadIZN4ceph5async15io_context_pool5startEsEUlvE_JEES_St17basic_string_viewIcSt11char_traitsIcEEOT_DpOT0_EUlSD_SG_E_S7_EEEEEE@Base 16.2.6+ds ++ _ZTVNSt6thread11_State_implINS_8_InvokerISt5tupleIJZ17make_named_threadIZN4ceph5async15io_context_pool5startEsEUlvE_JEES_St17basic_string_viewIcSt11char_traitsIcEEOT_DpOT0_EUlSD_SG_E_S7_EEEEEE@Base 16.2.6+ds ++ ceph_abort_conn@Base 14.2.0 ++ ceph_buffer_free@Base 12.0.3 ++ ceph_chdir@Base 12.0.3 ++ ceph_chmod@Base 12.0.3 ++ ceph_chmodat@Base 16.2.6+ds ++ ceph_chown@Base 12.0.3 ++ ceph_chownat@Base 16.2.6+ds ++ ceph_close@Base 12.0.3 ++ ceph_closedir@Base 12.0.3 ++ ceph_conf_get@Base 12.0.3 ++ ceph_conf_parse_argv@Base 12.0.3 ++ ceph_conf_parse_env@Base 12.0.3 ++ ceph_conf_read_file@Base 12.0.3 ++ ceph_conf_set@Base 12.0.3 ++ ceph_create@Base 12.0.3 ++ ceph_create_from_rados@Base 12.0.3 ++ ceph_create_with_context@Base 12.0.3 ++ ceph_debug_get_fd_caps@Base 12.0.3 ++ ceph_debug_get_file_caps@Base 12.0.3 ++ ceph_fallocate@Base 12.0.3 ++ ceph_fchmod@Base 12.0.3 ++ ceph_fchown@Base 12.0.3 ++ ceph_fdopendir@Base 16.2.6+ds ++ ceph_fgetxattr@Base 12.0.3 ++ ceph_finish_reclaim@Base 14.2.0 ++ ceph_flistxattr@Base 12.0.3 ++ ceph_flock@Base 12.0.3 ++ ceph_free_snap_info_buffer@Base 16.2.6+ds ++ ceph_fremovexattr@Base 12.0.3 ++ ceph_fsetattrx@Base 12.0.3 ++ ceph_fsetxattr@Base 12.0.3 ++ ceph_fstat@Base 14.2.0 ++ ceph_fstatx@Base 12.0.3 ++ ceph_fsync@Base 12.0.3 ++ ceph_ftruncate@Base 12.0.3 ++ ceph_futime@Base 14.2.0 ++ ceph_futimens@Base 14.2.0 ++ ceph_futimes@Base 14.2.0 ++ ceph_get_cap_return_timeout@Base 13.2.0 ++ ceph_get_default_data_pool_name@Base 12.1.4 ++ ceph_get_file_extent_osds@Base 12.0.3 ++ ceph_get_file_layout@Base 12.0.3 ++ ceph_get_file_object_size@Base 12.0.3 ++ ceph_get_file_pool@Base 12.0.3 ++ ceph_get_file_pool_name@Base 12.0.3 ++ ceph_get_file_replication@Base 12.0.3 ++ ceph_get_file_stripe_address@Base 12.0.3 ++ ceph_get_file_stripe_count@Base 12.0.3 ++ ceph_get_file_stripe_unit@Base 12.0.3 ++ ceph_get_fs_cid@Base 14.2.0 ++ ceph_get_instance_id@Base 14.2.0 ++ ceph_get_local_osd@Base 12.0.3 ++ ceph_get_mount_context@Base 12.0.3 ++ ceph_get_osd_addr@Base 12.0.3 ++ ceph_get_osd_crush_location@Base 12.0.3 ++ ceph_get_path_layout@Base 12.0.3 ++ ceph_get_path_object_size@Base 12.0.3 ++ ceph_get_path_pool@Base 12.0.3 ++ ceph_get_path_pool_name@Base 12.0.3 ++ ceph_get_path_replication@Base 12.0.3 ++ ceph_get_path_stripe_count@Base 12.0.3 ++ ceph_get_path_stripe_unit@Base 12.0.3 ++ ceph_get_pool_id@Base 12.0.3 ++ ceph_get_pool_name@Base 12.0.3 ++ ceph_get_pool_replication@Base 12.0.3 ++ ceph_get_snap_info@Base 16.2.6+ds ++ ceph_get_stripe_unit_granularity@Base 12.0.3 ++ ceph_getaddrs@Base 16.2.6+ds ++ ceph_getcwd@Base 12.0.3 ++ ceph_getdents@Base 12.0.3 ++ ceph_getdnames@Base 12.0.3 ++ ceph_getxattr@Base 12.0.3 ++ ceph_init@Base 12.0.3 ++ ceph_is_mounted@Base 12.0.3 ++ ceph_lazyio@Base 14.2.0 ++ ceph_lazyio_propagate@Base 14.2.15 ++ ceph_lazyio_synchronize@Base 14.2.15 ++ ceph_lchmod@Base 16.2.6+ds ++ ceph_lchown@Base 12.0.3 ++ ceph_lgetxattr@Base 12.0.3 ++ ceph_link@Base 12.0.3 ++ ceph_listxattr@Base 12.0.3 ++ ceph_ll_close@Base 12.0.3 ++ ceph_ll_commit_blocks@Base 12.0.3 ++ ceph_ll_create@Base 12.0.3 ++ ceph_ll_delegation@Base 13.2.0 ++ ceph_ll_fallocate@Base 14.2.0 ++ ceph_ll_file_layout@Base 12.0.3 ++ ceph_ll_forget@Base 12.0.3 ++ ceph_ll_fsync@Base 12.0.3 ++ ceph_ll_get_inode@Base 12.0.3 ++ ceph_ll_get_internal_offset@Base 12.0.3 ++ ceph_ll_get_stripe_osd@Base 12.0.3 ++ ceph_ll_getattr@Base 12.0.3 ++ ceph_ll_getlk@Base 12.0.3 ++ ceph_ll_getxattr@Base 12.0.3 ++ ceph_ll_lazyio@Base 14.2.0 ++ ceph_ll_link@Base 12.0.3 ++ ceph_ll_listxattr@Base 12.0.3 ++ ceph_ll_lookup@Base 12.0.3 ++ ceph_ll_lookup_inode@Base 12.0.3 ++ ceph_ll_lookup_root@Base 12.0.3 ++ ceph_ll_lookup_vino@Base 16.2.6+ds ++ ceph_ll_lseek@Base 12.0.3 ++ ceph_ll_mkdir@Base 12.0.3 ++ ceph_ll_mknod@Base 12.0.3 ++ ceph_ll_num_osds@Base 12.0.3 ++ ceph_ll_open@Base 12.0.3 ++ ceph_ll_opendir@Base 12.0.3 ++ ceph_ll_osdaddr@Base 12.0.3 ++ ceph_ll_put@Base 12.0.3 ++ ceph_ll_read@Base 12.0.3 ++ ceph_ll_read_block@Base 12.0.3 ++ ceph_ll_readlink@Base 12.0.3 ++ ceph_ll_readv@Base 12.0.3 ++ ceph_ll_register_callbacks@Base 14.2.15 ++ ceph_ll_releasedir@Base 12.0.3 ++ ceph_ll_removexattr@Base 12.0.3 ++ ceph_ll_rename@Base 12.0.3 ++ ceph_ll_rmdir@Base 12.0.3 ++ ceph_ll_setattr@Base 12.0.3 ++ ceph_ll_setlk@Base 12.0.3 ++ ceph_ll_setxattr@Base 12.0.3 ++ ceph_ll_snap_seq@Base 12.0.3 ++ ceph_ll_statfs@Base 12.0.3 ++ ceph_ll_stripe_unit@Base 12.0.3 ++ ceph_ll_symlink@Base 12.0.3 ++ ceph_ll_sync_inode@Base 13.2.0 ++ ceph_ll_unlink@Base 12.0.3 ++ ceph_ll_walk@Base 12.0.3 ++ ceph_ll_write@Base 12.0.3 ++ ceph_ll_write_block@Base 12.0.3 ++ ceph_ll_writev@Base 12.0.3 ++ ceph_llistxattr@Base 12.0.3 ++ ceph_localize_reads@Base 12.0.3 ++ ceph_lremovexattr@Base 12.0.3 ++ ceph_lseek@Base 12.0.3 ++ ceph_lsetxattr@Base 12.0.3 ++ ceph_lstat@Base 14.2.0 ++ ceph_lutimes@Base 14.2.0 ++ ceph_may_delete@Base 16.2.6+ds ++ ceph_mds_command@Base 12.0.3 ++ ceph_mkdir@Base 12.0.3 ++ ceph_mkdirat@Base 16.2.6+ds ++ ceph_mkdirs@Base 12.0.3 ++ ceph_mknod@Base 12.0.3 ++ ceph_mksnap@Base 16.2.6+ds ++ ceph_mount@Base 12.0.3 ++ ceph_mount_perms@Base 12.0.3 ++ ceph_mount_perms_set@Base 13.2.0 ++ ceph_open@Base 12.0.3 ++ ceph_open_layout@Base 12.0.3 ++ ceph_openat@Base 16.2.6+ds ++ ceph_opendir@Base 12.0.3 ++ ceph_preadv@Base 12.0.3 ++ ceph_pwritev@Base 12.0.3 ++ ceph_read@Base 12.0.3 ++ ceph_readdir@Base 12.0.3 ++ ceph_readdir_r@Base 12.0.3 ++ ceph_readdirplus_r@Base 12.0.3 ++ ceph_readlink@Base 12.0.3 ++ ceph_readlinkat@Base 16.2.6+ds ++ ceph_release@Base 12.0.3 ++ ceph_removexattr@Base 12.0.3 ++ ceph_rename@Base 12.0.3 ++ ceph_rewinddir@Base 12.0.3 ++ ceph_rmdir@Base 12.0.3 ++ ceph_rmsnap@Base 16.2.6+ds ++ ceph_seekdir@Base 12.0.3 ++ ceph_select_filesystem@Base 14.2.0 ++ ceph_set_default_file_replication@Base 12.0.3 ++ ceph_set_default_file_stripe_count@Base 12.0.3 ++ ceph_set_default_file_stripe_unit@Base 12.0.3 ++ ceph_set_default_object_size@Base 12.0.3 ++ ceph_set_default_preferred_pg@Base 12.0.3 ++ ceph_set_deleg_timeout@Base 13.2.0 ++ ceph_set_mount_timeout@Base 16.2.6+ds ++ ceph_set_session_timeout@Base 14.2.0 ++ ceph_set_uuid@Base 14.2.0 ++ ceph_setattrx@Base 12.0.3 ++ ceph_setxattr@Base 12.0.3 ++ ceph_shutdown@Base 12.0.3 ++ ceph_start_reclaim@Base 14.2.0 ++ ceph_stat@Base 14.2.0 ++ ceph_statfs@Base 12.0.3 ++ ceph_statx@Base 12.0.3 ++ ceph_statxat@Base 16.2.6+ds ++ ceph_symlink@Base 12.0.3 ++ ceph_symlinkat@Base 16.2.6+ds ++ ceph_sync_fs@Base 12.0.3 ++ ceph_telldir@Base 12.0.3 ++ ceph_truncate@Base 12.0.3 ++ ceph_umask@Base 14.2.0 ++ ceph_unlink@Base 12.0.3 ++ ceph_unlinkat@Base 16.2.6+ds ++ ceph_unmount@Base 12.0.3 ++ ceph_userperm_destroy@Base 12.0.3 ++ ceph_userperm_new@Base 12.0.3 ++ ceph_utime@Base 12.0.3 ++ ceph_utimensat@Base 16.2.6+ds ++ ceph_utimes@Base 14.2.0 ++ ceph_version@Base 12.0.3 ++ ceph_write@Base 12.0.3 diff --cc debian/librados-dev.install index 000000000,000000000..edaa359fc new file mode 100644 --- /dev/null +++ b/debian/librados-dev.install @@@ -1,0 -1,0 +1,5 @@@ ++usr/bin/librados-config ++usr/include/rados/librados.h ++usr/include/rados/rados_types.h ++usr/lib/*/librados.so ++usr/share/man/man8/librados-config.8 diff --cc debian/librados2.install index 000000000,000000000..2020e29c4 new file mode 100644 --- /dev/null +++ b/debian/librados2.install @@@ -1,0 -1,0 +1,2 @@@ ++usr/lib/*/ceph/libceph-common.so* ++usr/lib/*/librados.so.* diff --cc debian/librados2.lintian-overrides index 000000000,000000000..d4041ca8e new file mode 100644 --- /dev/null +++ b/debian/librados2.lintian-overrides @@@ -1,0 -1,0 +1,2 @@@ ++# False-positives: ++spelling-error-in-binary * tEH the diff --cc debian/libradospp-dev.install index 000000000,000000000..749cdd772 new file mode 100644 --- /dev/null +++ b/debian/libradospp-dev.install @@@ -1,0 -1,0 +1,8 @@@ ++usr/include/rados/buffer.h ++usr/include/rados/buffer_fwd.h ++usr/include/rados/crc32c.h ++usr/include/rados/inline_memory.h ++usr/include/rados/librados.hpp ++usr/include/rados/librados_fwd.hpp ++usr/include/rados/page.h ++usr/include/rados/rados_types.hpp diff --cc debian/libradosstriper-dev.install index 000000000,000000000..4d6d7b5a0 new file mode 100644 --- /dev/null +++ b/debian/libradosstriper-dev.install @@@ -1,0 -1,0 +1,3 @@@ ++usr/include/radosstriper/libradosstriper.h ++usr/include/radosstriper/libradosstriper.hpp ++usr/lib/*/libradosstriper.so diff --cc debian/libradosstriper1.install index 000000000,000000000..742549ba9 new file mode 100644 --- /dev/null +++ b/debian/libradosstriper1.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/lib/*/libradosstriper.so.* diff --cc debian/libradosstriper1.symbols index 000000000,000000000..6da2d7c44 new file mode 100644 --- /dev/null +++ b/debian/libradosstriper1.symbols @@@ -1,0 -1,0 +1,47 @@@ ++libradosstriper.so.1 libradosstriper1 #MINVER# ++ (regex|c++)"^_.*" 0.87 ++ _ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJZ17make_named_threadIZN4ceph5async15io_context_pool5startEsEUlvE_JEES_St17basic_string_viewIcSt11char_traitsIcEEOT_DpOT0_EUlSD_SG_E_S7_EEEEE6_M_runEv@Base 16.2.6+ds ++ _ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJZ17make_named_threadIZN4ceph5async15io_context_pool5startEsEUlvE_JEES_St17basic_string_viewIcSt11char_traitsIcEEOT_DpOT0_EUlSD_SG_E_S7_EEEEED0Ev@Base 16.2.6+ds ++ _ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJZ17make_named_threadIZN4ceph5async15io_context_pool5startEsEUlvE_JEES_St17basic_string_viewIcSt11char_traitsIcEEOT_DpOT0_EUlSD_SG_E_S7_EEEEED1Ev@Base 16.2.6+ds ++ _ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJZ17make_named_threadIZN4ceph5async15io_context_pool5startEsEUlvE_JEES_St17basic_string_viewIcSt11char_traitsIcEEOT_DpOT0_EUlSD_SG_E_S7_EEEEED2Ev@Base 16.2.6+ds ++ _ZTINSt6thread11_State_implINS_8_InvokerISt5tupleIJZ17make_named_threadIZN4ceph5async15io_context_pool5startEsEUlvE_JEES_St17basic_string_viewIcSt11char_traitsIcEEOT_DpOT0_EUlSD_SG_E_S7_EEEEEE@Base 16.2.6+ds ++ _ZTSNSt6thread11_State_implINS_8_InvokerISt5tupleIJZ17make_named_threadIZN4ceph5async15io_context_pool5startEsEUlvE_JEES_St17basic_string_viewIcSt11char_traitsIcEEOT_DpOT0_EUlSD_SG_E_S7_EEEEEE@Base 16.2.6+ds ++ _ZTVNSt6thread11_State_implINS_8_InvokerISt5tupleIJZ17make_named_threadIZN4ceph5async15io_context_pool5startEsEUlvE_JEES_St17basic_string_viewIcSt11char_traitsIcEEOT_DpOT0_EUlSD_SG_E_S7_EEEEEE@Base 16.2.6+ds ++ boost_asio_detail_posix_thread_function@Base 16.2.6+ds ++ default_file_layout@Base 10.1.0 ++ rados_striper_aio_append@Base 0.87 ++ rados_striper_aio_flush@Base 0.87 ++ rados_striper_aio_read@Base 0.87 ++ rados_striper_aio_remove@Base 12.0.3 ++ rados_striper_aio_stat@Base 12.0.3 ++ rados_striper_aio_write@Base 0.87 ++ rados_striper_aio_write_full@Base 0.87 ++ rados_striper_append@Base 0.87 ++ rados_striper_create@Base 0.87 ++ rados_striper_destroy@Base 0.87 ++ rados_striper_getxattr@Base 0.87 ++ rados_striper_getxattrs@Base 0.87 ++ rados_striper_getxattrs_end@Base 0.87 ++ rados_striper_getxattrs_next@Base 0.87 ++ rados_striper_multi_aio_create_completion@Base 0.87 ++ rados_striper_multi_aio_get_return_value@Base 0.87 ++ rados_striper_multi_aio_is_complete@Base 0.87 ++ rados_striper_multi_aio_is_complete_and_cb@Base 0.87 ++ rados_striper_multi_aio_is_safe@Base 0.87 ++ rados_striper_multi_aio_is_safe_and_cb@Base 0.87 ++ rados_striper_multi_aio_release@Base 0.87 ++ rados_striper_multi_aio_wait_for_complete@Base 0.87 ++ rados_striper_multi_aio_wait_for_complete_and_cb@Base 0.87 ++ rados_striper_multi_aio_wait_for_safe@Base 0.87 ++ rados_striper_multi_aio_wait_for_safe_and_cb@Base 0.87 ++ rados_striper_read@Base 0.87 ++ rados_striper_remove@Base 0.87 ++ rados_striper_rmxattr@Base 0.87 ++ rados_striper_set_object_layout_object_size@Base 0.87 ++ rados_striper_set_object_layout_stripe_count@Base 0.87 ++ rados_striper_set_object_layout_stripe_unit@Base 0.87 ++ rados_striper_setxattr@Base 0.87 ++ rados_striper_stat@Base 0.87 ++ rados_striper_trunc@Base 0.87 ++ rados_striper_write@Base 0.87 ++ rados_striper_write_full@Base 0.87 diff --cc debian/librbd-dev.install index 000000000,000000000..c6b455e58 new file mode 100644 --- /dev/null +++ b/debian/librbd-dev.install @@@ -1,0 -1,0 +1,4 @@@ ++usr/include/rbd/features.h ++usr/include/rbd/librbd.h ++usr/include/rbd/librbd.hpp ++usr/lib/*/librbd.so diff --cc debian/librbd1.install index 000000000,000000000..decadbc19 new file mode 100644 --- /dev/null +++ b/debian/librbd1.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/lib/*/librbd.so.* diff --cc debian/librbd1.symbols index 000000000,000000000..f6e6c3368 new file mode 100644 --- /dev/null +++ b/debian/librbd1.symbols @@@ -1,0 -1,0 +1,281 @@@ ++librbd.so.1 librbd1 #MINVER# ++ (regex|c++)"^_.*" 0.87 ++ rbd_aio_close@Base 10.1.0 ++ rbd_aio_compare_and_write@Base 12.1.4 ++ rbd_aio_create_completion@Base 0.72.2 ++ rbd_aio_discard@Base 0.72.2 ++ rbd_aio_flush@Base 0.72.2 ++ rbd_aio_get_arg@Base 10.1.0 ++ rbd_aio_get_return_value@Base 0.72.2 ++ rbd_aio_is_complete@Base 0.72.2 ++ rbd_aio_mirror_image_create_snapshot@Base 16.2.6+ds ++ rbd_aio_mirror_image_demote@Base 12.0.3 ++ rbd_aio_mirror_image_get_global_status@Base 16.2.6+ds ++ rbd_aio_mirror_image_get_info@Base 12.0.3 ++ rbd_aio_mirror_image_get_mode@Base 16.2.6+ds ++ rbd_aio_mirror_image_get_status@Base 12.0.3 ++ rbd_aio_mirror_image_promote@Base 12.0.3 ++ rbd_aio_open@Base 10.1.0 ++ rbd_aio_open_by_id@Base 12.0.3 ++ rbd_aio_open_by_id_read_only@Base 12.0.3 ++ rbd_aio_open_read_only@Base 10.1.0 ++ rbd_aio_read2@Base 0.93 ++ rbd_aio_read@Base 0.72.2 ++ rbd_aio_readv@Base 12.0.3 ++ rbd_aio_release@Base 0.72.2 ++ rbd_aio_wait_for_complete@Base 0.72.2 ++ rbd_aio_write2@Base 0.93 ++ rbd_aio_write@Base 0.72.2 ++ rbd_aio_write_zeroes@Base 14.2.15 ++ rbd_aio_writesame@Base 12.0.3 ++ rbd_aio_writev@Base 12.0.3 ++ rbd_break_lock@Base 0.72.2 ++ rbd_clone2@Base 0.72.2 ++ rbd_clone3@Base 10.1.0 ++ rbd_clone@Base 0.72.2 ++ rbd_close@Base 0.72.2 ++ rbd_compare_and_write@Base 12.1.4 ++ rbd_config_image_list@Base 14.2.0 ++ rbd_config_image_list_cleanup@Base 14.2.0 ++ rbd_config_pool_list@Base 14.2.0 ++ rbd_config_pool_list_cleanup@Base 14.2.0 ++ rbd_copy2@Base 0.72.2 ++ rbd_copy3@Base 10.1.0 ++ rbd_copy4@Base 12.0.3 ++ rbd_copy@Base 0.72.2 ++ rbd_copy_with_progress2@Base 0.72.2 ++ rbd_copy_with_progress3@Base 12.0.3 ++ rbd_copy_with_progress4@Base 12.0.3 ++ rbd_copy_with_progress@Base 0.72.2 ++ rbd_create2@Base 0.72.2 ++ rbd_create3@Base 0.72.2 ++ rbd_create4@Base 10.1.0 ++ rbd_create@Base 0.72.2 ++ rbd_deep_copy@Base 13.2.0 ++ rbd_deep_copy_with_progress@Base 13.2.0 ++ rbd_diff_iterate2@Base 9.2.0 ++ rbd_diff_iterate@Base 0.72.2 ++ rbd_discard@Base 0.72.2 ++ rbd_encryption_format@Base 16.2.6+ds ++ rbd_encryption_load@Base 16.2.6+ds ++ rbd_features_from_string@Base 16.2.6+ds ++ rbd_features_to_string@Base 16.2.6+ds ++ rbd_flatten@Base 0.72.2 ++ rbd_flatten_with_progress@Base 12.0.3 ++ rbd_flush@Base 0.72.2 ++ rbd_get_access_timestamp@Base 14.2.0 ++ rbd_get_block_name_prefix@Base 12.0.3 ++ rbd_get_create_timestamp@Base 12.1.4 ++ rbd_get_data_pool_id@Base 12.0.3 ++ rbd_get_features@Base 0.72.2 ++ rbd_get_flags@Base 0.93 ++ rbd_get_group@Base 13.2.0 ++ rbd_get_id@Base 12.0.3 ++ rbd_get_migration_source_spec@Base 16.2.6+ds ++ rbd_get_modify_timestamp@Base 14.2.0 ++ rbd_get_name@Base 13.2.0 ++ rbd_get_old_format@Base 0.72.2 ++ rbd_get_op_features@Base 13.2.0 ++ rbd_get_overlap@Base 0.72.2 ++ rbd_get_parent@Base 14.2.0 ++ rbd_get_parent_info2@Base 12.0.3 ++ rbd_get_parent_info@Base 0.72.2 ++ rbd_get_size@Base 0.72.2 ++ rbd_get_stripe_count@Base 0.72.2 ++ rbd_get_stripe_unit@Base 0.72.2 ++ rbd_group_create@Base 13.2.0 ++ rbd_group_image_add@Base 13.2.0 ++ rbd_group_image_list@Base 13.2.0 ++ rbd_group_image_list_cleanup@Base 13.2.0 ++ rbd_group_image_remove@Base 13.2.0 ++ rbd_group_image_remove_by_id@Base 13.2.0 ++ rbd_group_info_cleanup@Base 13.2.0 ++ rbd_group_list@Base 13.2.0 ++ rbd_group_remove@Base 13.2.0 ++ rbd_group_rename@Base 13.2.0 ++ rbd_group_snap_create2@Base 16.2.6+ds ++ rbd_group_snap_create@Base 13.2.0 ++ rbd_group_snap_list@Base 13.2.0 ++ rbd_group_snap_list_cleanup@Base 13.2.0 ++ rbd_group_snap_remove@Base 13.2.0 ++ rbd_group_snap_rename@Base 13.2.0 ++ rbd_group_snap_rollback@Base 14.2.0 ++ rbd_group_snap_rollback_with_progress@Base 14.2.0 ++ rbd_image_options_clear@Base 10.1.0 ++ rbd_image_options_create@Base 10.1.0 ++ rbd_image_options_destroy@Base 10.1.0 ++ rbd_image_options_get_string@Base 10.1.0 ++ rbd_image_options_get_uint64@Base 10.1.0 ++ rbd_image_options_is_empty@Base 10.1.0 ++ rbd_image_options_is_set@Base 12.0.3 ++ rbd_image_options_set_string@Base 10.1.0 ++ rbd_image_options_set_uint64@Base 10.1.0 ++ rbd_image_options_unset@Base 10.1.0 ++ rbd_image_spec_cleanup@Base 14.2.0 ++ rbd_image_spec_list_cleanup@Base 14.2.0 ++ rbd_invalidate_cache@Base 0.80.5-2~ ++ rbd_is_exclusive_lock_owner@Base 0.93 ++ rbd_linked_image_spec_cleanup@Base 14.2.0 ++ rbd_linked_image_spec_list_cleanup@Base 14.2.0 ++ rbd_list2@Base 14.2.0 ++ rbd_list@Base 0.72.2 ++ rbd_list_child_cleanup@Base 13.2.0 ++ rbd_list_children2@Base 13.2.0 ++ rbd_list_children3@Base 14.2.0 ++ rbd_list_children@Base 0.72.2 ++ rbd_list_children_cleanup@Base 13.2.0 ++ rbd_list_descendants@Base 14.2.0 ++ rbd_list_lockers@Base 0.72.2 ++ rbd_lock_acquire@Base 12.0.3 ++ rbd_lock_break@Base 12.0.3 ++ rbd_lock_exclusive@Base 0.72.2 ++ rbd_lock_get_owners@Base 12.0.3 ++ rbd_lock_get_owners_cleanup@Base 12.0.3 ++ rbd_lock_release@Base 12.0.3 ++ rbd_lock_shared@Base 0.72.2 ++ rbd_metadata_get@Base 9.2.0 ++ rbd_metadata_list@Base 9.2.0 ++ rbd_metadata_remove@Base 9.2.0 ++ rbd_metadata_set@Base 9.2.0 ++ rbd_migration_abort@Base 14.2.0 ++ rbd_migration_abort_with_progress@Base 14.2.0 ++ rbd_migration_commit@Base 14.2.0 ++ rbd_migration_commit_with_progress@Base 14.2.0 ++ rbd_migration_execute@Base 14.2.0 ++ rbd_migration_execute_with_progress@Base 14.2.0 ++ rbd_migration_prepare@Base 14.2.0 ++ rbd_migration_prepare_import@Base 16.2.6+ds ++ rbd_migration_status@Base 14.2.0 ++ rbd_migration_status_cleanup@Base 14.2.0 ++ rbd_mirror_image_create_snapshot2@Base 16.2.6+ds ++ rbd_mirror_image_create_snapshot@Base 16.2.6+ds ++ rbd_mirror_image_demote@Base 10.1.0 ++ rbd_mirror_image_disable@Base 10.1.0 ++ rbd_mirror_image_enable2@Base 16.2.6+ds ++ rbd_mirror_image_enable@Base 10.1.0 ++ rbd_mirror_image_get_global_status@Base 16.2.6+ds ++ rbd_mirror_image_get_info@Base 10.1.0 ++ rbd_mirror_image_get_info_cleanup@Base 16.2.6+ds ++ rbd_mirror_image_get_instance_id@Base 14.2.0 ++ rbd_mirror_image_get_mode@Base 16.2.6+ds ++ rbd_mirror_image_get_status@Base 12.0.3 ++ rbd_mirror_image_global_status_cleanup@Base 16.2.6+ds ++ rbd_mirror_image_global_status_list@Base 16.2.6+ds ++ rbd_mirror_image_global_status_list_cleanup@Base 16.2.6+ds ++ rbd_mirror_image_info_list@Base 16.2.6+ds ++ rbd_mirror_image_info_list_cleanup@Base 16.2.6+ds ++ rbd_mirror_image_instance_id_list@Base 14.2.0 ++ rbd_mirror_image_instance_id_list_cleanup@Base 14.2.0 ++ rbd_mirror_image_promote@Base 10.1.0 ++ rbd_mirror_image_resync@Base 10.1.0 ++ rbd_mirror_image_status_list@Base 12.0.3 ++ rbd_mirror_image_status_list_cleanup@Base 12.0.3 ++ rbd_mirror_image_status_summary@Base 12.0.3 ++ rbd_mirror_mode_get@Base 10.1.0 ++ rbd_mirror_mode_set@Base 10.1.0 ++ rbd_mirror_peer_add@Base 10.1.0 ++ rbd_mirror_peer_bootstrap_create@Base 14.2.5 ++ rbd_mirror_peer_bootstrap_import@Base 14.2.5 ++ rbd_mirror_peer_get_attributes@Base 14.2.0 ++ rbd_mirror_peer_list@Base 10.1.0 ++ rbd_mirror_peer_list_cleanup@Base 10.1.0 ++ rbd_mirror_peer_remove@Base 10.1.0 ++ rbd_mirror_peer_set_attributes@Base 14.2.0 ++ rbd_mirror_peer_set_client@Base 10.1.0 ++ rbd_mirror_peer_set_cluster@Base 10.1.0 ++ rbd_mirror_peer_site_add@Base 16.2.6+ds ++ rbd_mirror_peer_site_get_attributes@Base 16.2.6+ds ++ rbd_mirror_peer_site_list@Base 16.2.6+ds ++ rbd_mirror_peer_site_list_cleanup@Base 16.2.6+ds ++ rbd_mirror_peer_site_remove@Base 16.2.6+ds ++ rbd_mirror_peer_site_set_attributes@Base 16.2.6+ds ++ rbd_mirror_peer_site_set_client_name@Base 16.2.6+ds ++ rbd_mirror_peer_site_set_direction@Base 16.2.6+ds ++ rbd_mirror_peer_site_set_name@Base 16.2.6+ds ++ rbd_mirror_site_name_get@Base 14.2.5 ++ rbd_mirror_site_name_set@Base 14.2.5 ++ rbd_mirror_uuid_get@Base 16.2.6+ds ++ rbd_namespace_create@Base 14.2.0 ++ rbd_namespace_exists@Base 14.2.0 ++ rbd_namespace_list@Base 14.2.0 ++ rbd_namespace_remove@Base 14.2.0 ++ rbd_open@Base 0.72.2 ++ rbd_open_by_id@Base 12.0.3 ++ rbd_open_by_id_read_only@Base 12.0.3 ++ rbd_open_read_only@Base 0.72.2 ++ rbd_poll_io_events@Base 10.1.0 ++ rbd_pool_init@Base 14.2.0 ++ rbd_pool_metadata_get@Base 14.2.0 ++ rbd_pool_metadata_list@Base 14.2.0 ++ rbd_pool_metadata_remove@Base 14.2.0 ++ rbd_pool_metadata_set@Base 14.2.0 ++ rbd_pool_stats_create@Base 14.2.0 ++ rbd_pool_stats_destroy@Base 14.2.0 ++ rbd_pool_stats_get@Base 14.2.0 ++ rbd_pool_stats_option_add_uint64@Base 14.2.0 ++ rbd_quiesce_unwatch@Base 16.2.6+ds ++ rbd_quiesce_watch@Base 16.2.6+ds ++ rbd_read2@Base 0.93 ++ rbd_read@Base 0.72.2 ++ rbd_read_iterate2@Base 0.72.2 ++ rbd_read_iterate@Base 0.72.2 ++ rbd_rebuild_object_map@Base 9.2.0 ++ rbd_remove@Base 0.72.2 ++ rbd_remove_with_progress@Base 0.72.2 ++ rbd_rename@Base 0.72.2 ++ rbd_resize2@Base 12.0.3 ++ rbd_resize@Base 0.72.2 ++ rbd_resize_with_progress@Base 0.72.2 ++ rbd_set_image_notification@Base 10.1.0 ++ rbd_snap_create2@Base 16.2.6+ds ++ rbd_snap_create@Base 0.72.2 ++ rbd_snap_exists@Base 16.2.6+ds ++ rbd_snap_get_group_namespace@Base 13.2.0 ++ rbd_snap_get_id@Base 16.2.6+ds ++ rbd_snap_get_limit@Base 12.0.3 ++ rbd_snap_get_mirror_namespace@Base 16.2.6+ds ++ rbd_snap_get_name@Base 16.2.6+ds ++ rbd_snap_get_namespace_type@Base 13.2.0 ++ rbd_snap_get_timestamp@Base 12.0.3 ++ rbd_snap_get_trash_namespace@Base 14.2.0 ++ rbd_snap_group_namespace_cleanup@Base 13.2.0 ++ rbd_snap_is_protected@Base 0.72.2 ++ rbd_snap_list@Base 0.72.2 ++ rbd_snap_list_end@Base 0.72.2 ++ rbd_snap_mirror_namespace_cleanup@Base 16.2.6+ds ++ rbd_snap_protect@Base 0.72.2 ++ rbd_snap_remove2@Base 12.0.3 ++ rbd_snap_remove@Base 0.72.2 ++ rbd_snap_remove_by_id@Base 14.2.0 ++ rbd_snap_rename@Base 10.1.0 ++ rbd_snap_rollback@Base 0.72.2 ++ rbd_snap_rollback_with_progress@Base 0.72.2 ++ rbd_snap_set@Base 0.72.2 ++ rbd_snap_set_by_id@Base 13.2.0 ++ rbd_snap_set_limit@Base 12.0.3 ++ rbd_snap_spec_cleanup@Base 14.2.0 ++ rbd_snap_unprotect@Base 0.72.2 ++ rbd_sparsify@Base 14.2.0 ++ rbd_sparsify_with_progress@Base 14.2.0 ++ rbd_stat@Base 0.72.2 ++ rbd_trash_get@Base 12.0.3 ++ rbd_trash_get_cleanup@Base 12.0.3 ++ rbd_trash_list@Base 12.0.3 ++ rbd_trash_list_cleanup@Base 12.0.3 ++ rbd_trash_move@Base 12.0.3 ++ rbd_trash_purge@Base 14.2.0 ++ rbd_trash_purge_with_progress@Base 14.2.0 ++ rbd_trash_remove@Base 12.0.3 ++ rbd_trash_remove_with_progress@Base 12.0.3 ++ rbd_trash_restore@Base 12.0.3 ++ rbd_unlock@Base 0.72.2 ++ rbd_update_features@Base 9.2.0 ++ rbd_update_unwatch@Base 12.0.3 ++ rbd_update_watch@Base 12.0.3 ++ rbd_version@Base 0.72.2 ++ rbd_watchers_list@Base 13.2.0 ++ rbd_watchers_list_cleanup@Base 13.2.0 ++ rbd_write2@Base 0.93 ++ rbd_write@Base 0.72.2 ++ rbd_write_zeroes@Base 14.2.15 ++ rbd_writesame@Base 12.0.3 diff --cc debian/librgw-dev.install index 000000000,000000000..56d4da008 new file mode 100644 --- /dev/null +++ b/debian/librgw-dev.install @@@ -1,0 -1,0 +1,3 @@@ ++usr/include/rados/librgw.h ++usr/include/rados/rgw_file.h ++usr/lib/*/librgw.so diff --cc debian/librgw2.install index 000000000,000000000..267c56113 new file mode 100644 --- /dev/null +++ b/debian/librgw2.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/lib/*/librgw.so.* diff --cc debian/libsqlite3-mod-ceph-dev.install index 000000000,000000000..8c696d069 new file mode 100644 --- /dev/null +++ b/debian/libsqlite3-mod-ceph-dev.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/include/libcephsqlite.h diff --cc debian/libsqlite3-mod-ceph.install index 000000000,000000000..c33877245 new file mode 100644 --- /dev/null +++ b/debian/libsqlite3-mod-ceph.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/lib/*/libcephsqlite.so diff --cc debian/man/ceph-crush-location.1 index 000000000,000000000..d05d85c7b new file mode 100644 --- /dev/null +++ b/debian/man/ceph-crush-location.1 @@@ -1,0 -1,0 +1,24 @@@ ++.TH ceph-crush-location "1" "April 2014" "ceph-crush-location" "User Commands" ++.SH NAME ++ceph-crush-location \- get CRUSH location ++.SH DESCRIPTION ++Generate a CRUSH location for the given entity ++ ++The CRUSH location consists of a list of key=value pairs, separated ++by spaces, all on a single line. This describes where in CRUSH ++hierarhcy this entity should be placed. ++ ++.SH OPTIONS ++.TP 4 ++\fB\-\-cluster\fR ++name of the cluster (see /etc/ceph/$cluster.conf) ++.TP 4 ++\fB\-\-type\fR ++daemon/entity type ++.TP 4 ++\fB\-\-id\fR ++id (osd number, mds name, client name) ++ ++.SH SEE ALSO ++.TP ++\fBceph-conf\fP(8) diff --cc debian/man/mount.fuse.ceph.8 index 000000000,000000000..718936578 new file mode 100644 --- /dev/null +++ b/debian/man/mount.fuse.ceph.8 @@@ -1,0 -1,0 +1,30 @@@ ++.TH mount.fuse.ceph "8" "March 2014" "ceph-fuse" "User Commands" ++.SH NAME ++mount.fuse.ceph \- wrapper around ceph-fuse ++.SH DESCRIPTION ++Helper to mount ceph-fuse from /etc/fstab. To use, add an entry like: ++ ++.nf ++# DEVICE PATH TYPE OPTIONS ++ mount.fuse.ceph#conf=/etc/ceph/ceph.conf,id=admin /mnt/ceph fuse _netdev,noatime,allow_other 0 0 ++ mount.fuse.ceph#conf=/etc/ceph/foo.conf,id=myuser /mnt/ceph2 fuse _netdev,noatime,allow_other 0 0 ++.fi ++ ++where the device field is a comma-separated list of options to pass on ++the command line. The examples above, for example, specify that ++ceph-fuse will authenticated as client.admin and client.myuser ++(respectively), and the second example also sets the "conf" option to ++"/etc/ceph/foo.conf" via the ceph-fuse command line. Any valid ++ceph-fuse option can be passed in this way. ++ ++.SH OPTIONS ++.TP 4 ++\fB\-\-conf\fR ++path to ceph cponfiguration file, usually "/etc/ceph/ceph.conf" ++.TP 4 ++\fB\-\-id\fR ++user name ++ ++.SH SEE ALSO ++.TP ++\fBceph-fuse\fP(8) diff --cc debian/missing-sources/bootstrap.js index 000000000,000000000..8a2e99a53 new file mode 100644 --- /dev/null +++ b/debian/missing-sources/bootstrap.js @@@ -1,0 -1,0 +1,2377 @@@ ++/*! ++ * Bootstrap v3.3.7 (http://getbootstrap.com) ++ * Copyright 2011-2016 Twitter, Inc. ++ * Licensed under the MIT license ++ */ ++ ++if (typeof jQuery === 'undefined') { ++ throw new Error('Bootstrap\'s JavaScript requires jQuery') ++} ++ +++function ($) { ++ 'use strict'; ++ var version = $.fn.jquery.split(' ')[0].split('.') ++ if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) { ++ throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4') ++ } ++}(jQuery); ++ ++/* ======================================================================== ++ * Bootstrap: transition.js v3.3.7 ++ * http://getbootstrap.com/javascript/#transitions ++ * ======================================================================== ++ * Copyright 2011-2016 Twitter, Inc. ++ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) ++ * ======================================================================== */ ++ ++ +++function ($) { ++ 'use strict'; ++ ++ // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) ++ // ============================================================ ++ ++ function transitionEnd() { ++ var el = document.createElement('bootstrap') ++ ++ var transEndEventNames = { ++ WebkitTransition : 'webkitTransitionEnd', ++ MozTransition : 'transitionend', ++ OTransition : 'oTransitionEnd otransitionend', ++ transition : 'transitionend' ++ } ++ ++ for (var name in transEndEventNames) { ++ if (el.style[name] !== undefined) { ++ return { end: transEndEventNames[name] } ++ } ++ } ++ ++ return false // explicit for ie8 ( ._.) ++ } ++ ++ // http://blog.alexmaccaw.com/css-transitions ++ $.fn.emulateTransitionEnd = function (duration) { ++ var called = false ++ var $el = this ++ $(this).one('bsTransitionEnd', function () { called = true }) ++ var callback = function () { if (!called) $($el).trigger($.support.transition.end) } ++ setTimeout(callback, duration) ++ return this ++ } ++ ++ $(function () { ++ $.support.transition = transitionEnd() ++ ++ if (!$.support.transition) return ++ ++ $.event.special.bsTransitionEnd = { ++ bindType: $.support.transition.end, ++ delegateType: $.support.transition.end, ++ handle: function (e) { ++ if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) ++ } ++ } ++ }) ++ ++}(jQuery); ++ ++/* ======================================================================== ++ * Bootstrap: alert.js v3.3.7 ++ * http://getbootstrap.com/javascript/#alerts ++ * ======================================================================== ++ * Copyright 2011-2016 Twitter, Inc. ++ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) ++ * ======================================================================== */ ++ ++ +++function ($) { ++ 'use strict'; ++ ++ // ALERT CLASS DEFINITION ++ // ====================== ++ ++ var dismiss = '[data-dismiss="alert"]' ++ var Alert = function (el) { ++ $(el).on('click', dismiss, this.close) ++ } ++ ++ Alert.VERSION = '3.3.7' ++ ++ Alert.TRANSITION_DURATION = 150 ++ ++ Alert.prototype.close = function (e) { ++ var $this = $(this) ++ var selector = $this.attr('data-target') ++ ++ if (!selector) { ++ selector = $this.attr('href') ++ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 ++ } ++ ++ var $parent = $(selector === '#' ? [] : selector) ++ ++ if (e) e.preventDefault() ++ ++ if (!$parent.length) { ++ $parent = $this.closest('.alert') ++ } ++ ++ $parent.trigger(e = $.Event('close.bs.alert')) ++ ++ if (e.isDefaultPrevented()) return ++ ++ $parent.removeClass('in') ++ ++ function removeElement() { ++ // detach from parent, fire event then clean up data ++ $parent.detach().trigger('closed.bs.alert').remove() ++ } ++ ++ $.support.transition && $parent.hasClass('fade') ? ++ $parent ++ .one('bsTransitionEnd', removeElement) ++ .emulateTransitionEnd(Alert.TRANSITION_DURATION) : ++ removeElement() ++ } ++ ++ ++ // ALERT PLUGIN DEFINITION ++ // ======================= ++ ++ function Plugin(option) { ++ return this.each(function () { ++ var $this = $(this) ++ var data = $this.data('bs.alert') ++ ++ if (!data) $this.data('bs.alert', (data = new Alert(this))) ++ if (typeof option == 'string') data[option].call($this) ++ }) ++ } ++ ++ var old = $.fn.alert ++ ++ $.fn.alert = Plugin ++ $.fn.alert.Constructor = Alert ++ ++ ++ // ALERT NO CONFLICT ++ // ================= ++ ++ $.fn.alert.noConflict = function () { ++ $.fn.alert = old ++ return this ++ } ++ ++ ++ // ALERT DATA-API ++ // ============== ++ ++ $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) ++ ++}(jQuery); ++ ++/* ======================================================================== ++ * Bootstrap: button.js v3.3.7 ++ * http://getbootstrap.com/javascript/#buttons ++ * ======================================================================== ++ * Copyright 2011-2016 Twitter, Inc. ++ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) ++ * ======================================================================== */ ++ ++ +++function ($) { ++ 'use strict'; ++ ++ // BUTTON PUBLIC CLASS DEFINITION ++ // ============================== ++ ++ var Button = function (element, options) { ++ this.$element = $(element) ++ this.options = $.extend({}, Button.DEFAULTS, options) ++ this.isLoading = false ++ } ++ ++ Button.VERSION = '3.3.7' ++ ++ Button.DEFAULTS = { ++ loadingText: 'loading...' ++ } ++ ++ Button.prototype.setState = function (state) { ++ var d = 'disabled' ++ var $el = this.$element ++ var val = $el.is('input') ? 'val' : 'html' ++ var data = $el.data() ++ ++ state += 'Text' ++ ++ if (data.resetText == null) $el.data('resetText', $el[val]()) ++ ++ // push to event loop to allow forms to submit ++ setTimeout($.proxy(function () { ++ $el[val](data[state] == null ? this.options[state] : data[state]) ++ ++ if (state == 'loadingText') { ++ this.isLoading = true ++ $el.addClass(d).attr(d, d).prop(d, true) ++ } else if (this.isLoading) { ++ this.isLoading = false ++ $el.removeClass(d).removeAttr(d).prop(d, false) ++ } ++ }, this), 0) ++ } ++ ++ Button.prototype.toggle = function () { ++ var changed = true ++ var $parent = this.$element.closest('[data-toggle="buttons"]') ++ ++ if ($parent.length) { ++ var $input = this.$element.find('input') ++ if ($input.prop('type') == 'radio') { ++ if ($input.prop('checked')) changed = false ++ $parent.find('.active').removeClass('active') ++ this.$element.addClass('active') ++ } else if ($input.prop('type') == 'checkbox') { ++ if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false ++ this.$element.toggleClass('active') ++ } ++ $input.prop('checked', this.$element.hasClass('active')) ++ if (changed) $input.trigger('change') ++ } else { ++ this.$element.attr('aria-pressed', !this.$element.hasClass('active')) ++ this.$element.toggleClass('active') ++ } ++ } ++ ++ ++ // BUTTON PLUGIN DEFINITION ++ // ======================== ++ ++ function Plugin(option) { ++ return this.each(function () { ++ var $this = $(this) ++ var data = $this.data('bs.button') ++ var options = typeof option == 'object' && option ++ ++ if (!data) $this.data('bs.button', (data = new Button(this, options))) ++ ++ if (option == 'toggle') data.toggle() ++ else if (option) data.setState(option) ++ }) ++ } ++ ++ var old = $.fn.button ++ ++ $.fn.button = Plugin ++ $.fn.button.Constructor = Button ++ ++ ++ // BUTTON NO CONFLICT ++ // ================== ++ ++ $.fn.button.noConflict = function () { ++ $.fn.button = old ++ return this ++ } ++ ++ ++ // BUTTON DATA-API ++ // =============== ++ ++ $(document) ++ .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { ++ var $btn = $(e.target).closest('.btn') ++ Plugin.call($btn, 'toggle') ++ if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) { ++ // Prevent double click on radios, and the double selections (so cancellation) on checkboxes ++ e.preventDefault() ++ // The target component still receive the focus ++ if ($btn.is('input,button')) $btn.trigger('focus') ++ else $btn.find('input:visible,button:visible').first().trigger('focus') ++ } ++ }) ++ .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { ++ $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) ++ }) ++ ++}(jQuery); ++ ++/* ======================================================================== ++ * Bootstrap: carousel.js v3.3.7 ++ * http://getbootstrap.com/javascript/#carousel ++ * ======================================================================== ++ * Copyright 2011-2016 Twitter, Inc. ++ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) ++ * ======================================================================== */ ++ ++ +++function ($) { ++ 'use strict'; ++ ++ // CAROUSEL CLASS DEFINITION ++ // ========================= ++ ++ var Carousel = function (element, options) { ++ this.$element = $(element) ++ this.$indicators = this.$element.find('.carousel-indicators') ++ this.options = options ++ this.paused = null ++ this.sliding = null ++ this.interval = null ++ this.$active = null ++ this.$items = null ++ ++ this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) ++ ++ this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element ++ .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) ++ .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) ++ } ++ ++ Carousel.VERSION = '3.3.7' ++ ++ Carousel.TRANSITION_DURATION = 600 ++ ++ Carousel.DEFAULTS = { ++ interval: 5000, ++ pause: 'hover', ++ wrap: true, ++ keyboard: true ++ } ++ ++ Carousel.prototype.keydown = function (e) { ++ if (/input|textarea/i.test(e.target.tagName)) return ++ switch (e.which) { ++ case 37: this.prev(); break ++ case 39: this.next(); break ++ default: return ++ } ++ ++ e.preventDefault() ++ } ++ ++ Carousel.prototype.cycle = function (e) { ++ e || (this.paused = false) ++ ++ this.interval && clearInterval(this.interval) ++ ++ this.options.interval ++ && !this.paused ++ && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) ++ ++ return this ++ } ++ ++ Carousel.prototype.getItemIndex = function (item) { ++ this.$items = item.parent().children('.item') ++ return this.$items.index(item || this.$active) ++ } ++ ++ Carousel.prototype.getItemForDirection = function (direction, active) { ++ var activeIndex = this.getItemIndex(active) ++ var willWrap = (direction == 'prev' && activeIndex === 0) ++ || (direction == 'next' && activeIndex == (this.$items.length - 1)) ++ if (willWrap && !this.options.wrap) return active ++ var delta = direction == 'prev' ? -1 : 1 ++ var itemIndex = (activeIndex + delta) % this.$items.length ++ return this.$items.eq(itemIndex) ++ } ++ ++ Carousel.prototype.to = function (pos) { ++ var that = this ++ var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) ++ ++ if (pos > (this.$items.length - 1) || pos < 0) return ++ ++ if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" ++ if (activeIndex == pos) return this.pause().cycle() ++ ++ return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) ++ } ++ ++ Carousel.prototype.pause = function (e) { ++ e || (this.paused = true) ++ ++ if (this.$element.find('.next, .prev').length && $.support.transition) { ++ this.$element.trigger($.support.transition.end) ++ this.cycle(true) ++ } ++ ++ this.interval = clearInterval(this.interval) ++ ++ return this ++ } ++ ++ Carousel.prototype.next = function () { ++ if (this.sliding) return ++ return this.slide('next') ++ } ++ ++ Carousel.prototype.prev = function () { ++ if (this.sliding) return ++ return this.slide('prev') ++ } ++ ++ Carousel.prototype.slide = function (type, next) { ++ var $active = this.$element.find('.item.active') ++ var $next = next || this.getItemForDirection(type, $active) ++ var isCycling = this.interval ++ var direction = type == 'next' ? 'left' : 'right' ++ var that = this ++ ++ if ($next.hasClass('active')) return (this.sliding = false) ++ ++ var relatedTarget = $next[0] ++ var slideEvent = $.Event('slide.bs.carousel', { ++ relatedTarget: relatedTarget, ++ direction: direction ++ }) ++ this.$element.trigger(slideEvent) ++ if (slideEvent.isDefaultPrevented()) return ++ ++ this.sliding = true ++ ++ isCycling && this.pause() ++ ++ if (this.$indicators.length) { ++ this.$indicators.find('.active').removeClass('active') ++ var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) ++ $nextIndicator && $nextIndicator.addClass('active') ++ } ++ ++ var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" ++ if ($.support.transition && this.$element.hasClass('slide')) { ++ $next.addClass(type) ++ $next[0].offsetWidth // force reflow ++ $active.addClass(direction) ++ $next.addClass(direction) ++ $active ++ .one('bsTransitionEnd', function () { ++ $next.removeClass([type, direction].join(' ')).addClass('active') ++ $active.removeClass(['active', direction].join(' ')) ++ that.sliding = false ++ setTimeout(function () { ++ that.$element.trigger(slidEvent) ++ }, 0) ++ }) ++ .emulateTransitionEnd(Carousel.TRANSITION_DURATION) ++ } else { ++ $active.removeClass('active') ++ $next.addClass('active') ++ this.sliding = false ++ this.$element.trigger(slidEvent) ++ } ++ ++ isCycling && this.cycle() ++ ++ return this ++ } ++ ++ ++ // CAROUSEL PLUGIN DEFINITION ++ // ========================== ++ ++ function Plugin(option) { ++ return this.each(function () { ++ var $this = $(this) ++ var data = $this.data('bs.carousel') ++ var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) ++ var action = typeof option == 'string' ? option : options.slide ++ ++ if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) ++ if (typeof option == 'number') data.to(option) ++ else if (action) data[action]() ++ else if (options.interval) data.pause().cycle() ++ }) ++ } ++ ++ var old = $.fn.carousel ++ ++ $.fn.carousel = Plugin ++ $.fn.carousel.Constructor = Carousel ++ ++ ++ // CAROUSEL NO CONFLICT ++ // ==================== ++ ++ $.fn.carousel.noConflict = function () { ++ $.fn.carousel = old ++ return this ++ } ++ ++ ++ // CAROUSEL DATA-API ++ // ================= ++ ++ var clickHandler = function (e) { ++ var href ++ var $this = $(this) ++ var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 ++ if (!$target.hasClass('carousel')) return ++ var options = $.extend({}, $target.data(), $this.data()) ++ var slideIndex = $this.attr('data-slide-to') ++ if (slideIndex) options.interval = false ++ ++ Plugin.call($target, options) ++ ++ if (slideIndex) { ++ $target.data('bs.carousel').to(slideIndex) ++ } ++ ++ e.preventDefault() ++ } ++ ++ $(document) ++ .on('click.bs.carousel.data-api', '[data-slide]', clickHandler) ++ .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler) ++ ++ $(window).on('load', function () { ++ $('[data-ride="carousel"]').each(function () { ++ var $carousel = $(this) ++ Plugin.call($carousel, $carousel.data()) ++ }) ++ }) ++ ++}(jQuery); ++ ++/* ======================================================================== ++ * Bootstrap: collapse.js v3.3.7 ++ * http://getbootstrap.com/javascript/#collapse ++ * ======================================================================== ++ * Copyright 2011-2016 Twitter, Inc. ++ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) ++ * ======================================================================== */ ++ ++/* jshint latedef: false */ ++ +++function ($) { ++ 'use strict'; ++ ++ // COLLAPSE PUBLIC CLASS DEFINITION ++ // ================================ ++ ++ var Collapse = function (element, options) { ++ this.$element = $(element) ++ this.options = $.extend({}, Collapse.DEFAULTS, options) ++ this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' + ++ '[data-toggle="collapse"][data-target="#' + element.id + '"]') ++ this.transitioning = null ++ ++ if (this.options.parent) { ++ this.$parent = this.getParent() ++ } else { ++ this.addAriaAndCollapsedClass(this.$element, this.$trigger) ++ } ++ ++ if (this.options.toggle) this.toggle() ++ } ++ ++ Collapse.VERSION = '3.3.7' ++ ++ Collapse.TRANSITION_DURATION = 350 ++ ++ Collapse.DEFAULTS = { ++ toggle: true ++ } ++ ++ Collapse.prototype.dimension = function () { ++ var hasWidth = this.$element.hasClass('width') ++ return hasWidth ? 'width' : 'height' ++ } ++ ++ Collapse.prototype.show = function () { ++ if (this.transitioning || this.$element.hasClass('in')) return ++ ++ var activesData ++ var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing') ++ ++ if (actives && actives.length) { ++ activesData = actives.data('bs.collapse') ++ if (activesData && activesData.transitioning) return ++ } ++ ++ var startEvent = $.Event('show.bs.collapse') ++ this.$element.trigger(startEvent) ++ if (startEvent.isDefaultPrevented()) return ++ ++ if (actives && actives.length) { ++ Plugin.call(actives, 'hide') ++ activesData || actives.data('bs.collapse', null) ++ } ++ ++ var dimension = this.dimension() ++ ++ this.$element ++ .removeClass('collapse') ++ .addClass('collapsing')[dimension](0) ++ .attr('aria-expanded', true) ++ ++ this.$trigger ++ .removeClass('collapsed') ++ .attr('aria-expanded', true) ++ ++ this.transitioning = 1 ++ ++ var complete = function () { ++ this.$element ++ .removeClass('collapsing') ++ .addClass('collapse in')[dimension]('') ++ this.transitioning = 0 ++ this.$element ++ .trigger('shown.bs.collapse') ++ } ++ ++ if (!$.support.transition) return complete.call(this) ++ ++ var scrollSize = $.camelCase(['scroll', dimension].join('-')) ++ ++ this.$element ++ .one('bsTransitionEnd', $.proxy(complete, this)) ++ .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) ++ } ++ ++ Collapse.prototype.hide = function () { ++ if (this.transitioning || !this.$element.hasClass('in')) return ++ ++ var startEvent = $.Event('hide.bs.collapse') ++ this.$element.trigger(startEvent) ++ if (startEvent.isDefaultPrevented()) return ++ ++ var dimension = this.dimension() ++ ++ this.$element[dimension](this.$element[dimension]())[0].offsetHeight ++ ++ this.$element ++ .addClass('collapsing') ++ .removeClass('collapse in') ++ .attr('aria-expanded', false) ++ ++ this.$trigger ++ .addClass('collapsed') ++ .attr('aria-expanded', false) ++ ++ this.transitioning = 1 ++ ++ var complete = function () { ++ this.transitioning = 0 ++ this.$element ++ .removeClass('collapsing') ++ .addClass('collapse') ++ .trigger('hidden.bs.collapse') ++ } ++ ++ if (!$.support.transition) return complete.call(this) ++ ++ this.$element ++ [dimension](0) ++ .one('bsTransitionEnd', $.proxy(complete, this)) ++ .emulateTransitionEnd(Collapse.TRANSITION_DURATION) ++ } ++ ++ Collapse.prototype.toggle = function () { ++ this[this.$element.hasClass('in') ? 'hide' : 'show']() ++ } ++ ++ Collapse.prototype.getParent = function () { ++ return $(this.options.parent) ++ .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') ++ .each($.proxy(function (i, element) { ++ var $element = $(element) ++ this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) ++ }, this)) ++ .end() ++ } ++ ++ Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { ++ var isOpen = $element.hasClass('in') ++ ++ $element.attr('aria-expanded', isOpen) ++ $trigger ++ .toggleClass('collapsed', !isOpen) ++ .attr('aria-expanded', isOpen) ++ } ++ ++ function getTargetFromTrigger($trigger) { ++ var href ++ var target = $trigger.attr('data-target') ++ || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 ++ ++ return $(target) ++ } ++ ++ ++ // COLLAPSE PLUGIN DEFINITION ++ // ========================== ++ ++ function Plugin(option) { ++ return this.each(function () { ++ var $this = $(this) ++ var data = $this.data('bs.collapse') ++ var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) ++ ++ if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false ++ if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) ++ if (typeof option == 'string') data[option]() ++ }) ++ } ++ ++ var old = $.fn.collapse ++ ++ $.fn.collapse = Plugin ++ $.fn.collapse.Constructor = Collapse ++ ++ ++ // COLLAPSE NO CONFLICT ++ // ==================== ++ ++ $.fn.collapse.noConflict = function () { ++ $.fn.collapse = old ++ return this ++ } ++ ++ ++ // COLLAPSE DATA-API ++ // ================= ++ ++ $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { ++ var $this = $(this) ++ ++ if (!$this.attr('data-target')) e.preventDefault() ++ ++ var $target = getTargetFromTrigger($this) ++ var data = $target.data('bs.collapse') ++ var option = data ? 'toggle' : $this.data() ++ ++ Plugin.call($target, option) ++ }) ++ ++}(jQuery); ++ ++/* ======================================================================== ++ * Bootstrap: dropdown.js v3.3.7 ++ * http://getbootstrap.com/javascript/#dropdowns ++ * ======================================================================== ++ * Copyright 2011-2016 Twitter, Inc. ++ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) ++ * ======================================================================== */ ++ ++ +++function ($) { ++ 'use strict'; ++ ++ // DROPDOWN CLASS DEFINITION ++ // ========================= ++ ++ var backdrop = '.dropdown-backdrop' ++ var toggle = '[data-toggle="dropdown"]' ++ var Dropdown = function (element) { ++ $(element).on('click.bs.dropdown', this.toggle) ++ } ++ ++ Dropdown.VERSION = '3.3.7' ++ ++ function getParent($this) { ++ var selector = $this.attr('data-target') ++ ++ if (!selector) { ++ selector = $this.attr('href') ++ selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 ++ } ++ ++ var $parent = selector && $(selector) ++ ++ return $parent && $parent.length ? $parent : $this.parent() ++ } ++ ++ function clearMenus(e) { ++ if (e && e.which === 3) return ++ $(backdrop).remove() ++ $(toggle).each(function () { ++ var $this = $(this) ++ var $parent = getParent($this) ++ var relatedTarget = { relatedTarget: this } ++ ++ if (!$parent.hasClass('open')) return ++ ++ if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return ++ ++ $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget)) ++ ++ if (e.isDefaultPrevented()) return ++ ++ $this.attr('aria-expanded', 'false') ++ $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget)) ++ }) ++ } ++ ++ Dropdown.prototype.toggle = function (e) { ++ var $this = $(this) ++ ++ if ($this.is('.disabled, :disabled')) return ++ ++ var $parent = getParent($this) ++ var isActive = $parent.hasClass('open') ++ ++ clearMenus() ++ ++ if (!isActive) { ++ if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { ++ // if mobile we use a backdrop because click events don't delegate ++ $(document.createElement('div')) ++ .addClass('dropdown-backdrop') ++ .insertAfter($(this)) ++ .on('click', clearMenus) ++ } ++ ++ var relatedTarget = { relatedTarget: this } ++ $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget)) ++ ++ if (e.isDefaultPrevented()) return ++ ++ $this ++ .trigger('focus') ++ .attr('aria-expanded', 'true') ++ ++ $parent ++ .toggleClass('open') ++ .trigger($.Event('shown.bs.dropdown', relatedTarget)) ++ } ++ ++ return false ++ } ++ ++ Dropdown.prototype.keydown = function (e) { ++ if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return ++ ++ var $this = $(this) ++ ++ e.preventDefault() ++ e.stopPropagation() ++ ++ if ($this.is('.disabled, :disabled')) return ++ ++ var $parent = getParent($this) ++ var isActive = $parent.hasClass('open') ++ ++ if (!isActive && e.which != 27 || isActive && e.which == 27) { ++ if (e.which == 27) $parent.find(toggle).trigger('focus') ++ return $this.trigger('click') ++ } ++ ++ var desc = ' li:not(.disabled):visible a' ++ var $items = $parent.find('.dropdown-menu' + desc) ++ ++ if (!$items.length) return ++ ++ var index = $items.index(e.target) ++ ++ if (e.which == 38 && index > 0) index-- // up ++ if (e.which == 40 && index < $items.length - 1) index++ // down ++ if (!~index) index = 0 ++ ++ $items.eq(index).trigger('focus') ++ } ++ ++ ++ // DROPDOWN PLUGIN DEFINITION ++ // ========================== ++ ++ function Plugin(option) { ++ return this.each(function () { ++ var $this = $(this) ++ var data = $this.data('bs.dropdown') ++ ++ if (!data) $this.data('bs.dropdown', (data = new Dropdown(this))) ++ if (typeof option == 'string') data[option].call($this) ++ }) ++ } ++ ++ var old = $.fn.dropdown ++ ++ $.fn.dropdown = Plugin ++ $.fn.dropdown.Constructor = Dropdown ++ ++ ++ // DROPDOWN NO CONFLICT ++ // ==================== ++ ++ $.fn.dropdown.noConflict = function () { ++ $.fn.dropdown = old ++ return this ++ } ++ ++ ++ // APPLY TO STANDARD DROPDOWN ELEMENTS ++ // =================================== ++ ++ $(document) ++ .on('click.bs.dropdown.data-api', clearMenus) ++ .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) ++ .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle) ++ .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown) ++ .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown) ++ ++}(jQuery); ++ ++/* ======================================================================== ++ * Bootstrap: modal.js v3.3.7 ++ * http://getbootstrap.com/javascript/#modals ++ * ======================================================================== ++ * Copyright 2011-2016 Twitter, Inc. ++ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) ++ * ======================================================================== */ ++ ++ +++function ($) { ++ 'use strict'; ++ ++ // MODAL CLASS DEFINITION ++ // ====================== ++ ++ var Modal = function (element, options) { ++ this.options = options ++ this.$body = $(document.body) ++ this.$element = $(element) ++ this.$dialog = this.$element.find('.modal-dialog') ++ this.$backdrop = null ++ this.isShown = null ++ this.originalBodyPad = null ++ this.scrollbarWidth = 0 ++ this.ignoreBackdropClick = false ++ ++ if (this.options.remote) { ++ this.$element ++ .find('.modal-content') ++ .load(this.options.remote, $.proxy(function () { ++ this.$element.trigger('loaded.bs.modal') ++ }, this)) ++ } ++ } ++ ++ Modal.VERSION = '3.3.7' ++ ++ Modal.TRANSITION_DURATION = 300 ++ Modal.BACKDROP_TRANSITION_DURATION = 150 ++ ++ Modal.DEFAULTS = { ++ backdrop: true, ++ keyboard: true, ++ show: true ++ } ++ ++ Modal.prototype.toggle = function (_relatedTarget) { ++ return this.isShown ? this.hide() : this.show(_relatedTarget) ++ } ++ ++ Modal.prototype.show = function (_relatedTarget) { ++ var that = this ++ var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) ++ ++ this.$element.trigger(e) ++ ++ if (this.isShown || e.isDefaultPrevented()) return ++ ++ this.isShown = true ++ ++ this.checkScrollbar() ++ this.setScrollbar() ++ this.$body.addClass('modal-open') ++ ++ this.escape() ++ this.resize() ++ ++ this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) ++ ++ this.$dialog.on('mousedown.dismiss.bs.modal', function () { ++ that.$element.one('mouseup.dismiss.bs.modal', function (e) { ++ if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true ++ }) ++ }) ++ ++ this.backdrop(function () { ++ var transition = $.support.transition && that.$element.hasClass('fade') ++ ++ if (!that.$element.parent().length) { ++ that.$element.appendTo(that.$body) // don't move modals dom position ++ } ++ ++ that.$element ++ .show() ++ .scrollTop(0) ++ ++ that.adjustDialog() ++ ++ if (transition) { ++ that.$element[0].offsetWidth // force reflow ++ } ++ ++ that.$element.addClass('in') ++ ++ that.enforceFocus() ++ ++ var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) ++ ++ transition ? ++ that.$dialog // wait for modal to slide in ++ .one('bsTransitionEnd', function () { ++ that.$element.trigger('focus').trigger(e) ++ }) ++ .emulateTransitionEnd(Modal.TRANSITION_DURATION) : ++ that.$element.trigger('focus').trigger(e) ++ }) ++ } ++ ++ Modal.prototype.hide = function (e) { ++ if (e) e.preventDefault() ++ ++ e = $.Event('hide.bs.modal') ++ ++ this.$element.trigger(e) ++ ++ if (!this.isShown || e.isDefaultPrevented()) return ++ ++ this.isShown = false ++ ++ this.escape() ++ this.resize() ++ ++ $(document).off('focusin.bs.modal') ++ ++ this.$element ++ .removeClass('in') ++ .off('click.dismiss.bs.modal') ++ .off('mouseup.dismiss.bs.modal') ++ ++ this.$dialog.off('mousedown.dismiss.bs.modal') ++ ++ $.support.transition && this.$element.hasClass('fade') ? ++ this.$element ++ .one('bsTransitionEnd', $.proxy(this.hideModal, this)) ++ .emulateTransitionEnd(Modal.TRANSITION_DURATION) : ++ this.hideModal() ++ } ++ ++ Modal.prototype.enforceFocus = function () { ++ $(document) ++ .off('focusin.bs.modal') // guard against infinite focus loop ++ .on('focusin.bs.modal', $.proxy(function (e) { ++ if (document !== e.target && ++ this.$element[0] !== e.target && ++ !this.$element.has(e.target).length) { ++ this.$element.trigger('focus') ++ } ++ }, this)) ++ } ++ ++ Modal.prototype.escape = function () { ++ if (this.isShown && this.options.keyboard) { ++ this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) { ++ e.which == 27 && this.hide() ++ }, this)) ++ } else if (!this.isShown) { ++ this.$element.off('keydown.dismiss.bs.modal') ++ } ++ } ++ ++ Modal.prototype.resize = function () { ++ if (this.isShown) { ++ $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this)) ++ } else { ++ $(window).off('resize.bs.modal') ++ } ++ } ++ ++ Modal.prototype.hideModal = function () { ++ var that = this ++ this.$element.hide() ++ this.backdrop(function () { ++ that.$body.removeClass('modal-open') ++ that.resetAdjustments() ++ that.resetScrollbar() ++ that.$element.trigger('hidden.bs.modal') ++ }) ++ } ++ ++ Modal.prototype.removeBackdrop = function () { ++ this.$backdrop && this.$backdrop.remove() ++ this.$backdrop = null ++ } ++ ++ Modal.prototype.backdrop = function (callback) { ++ var that = this ++ var animate = this.$element.hasClass('fade') ? 'fade' : '' ++ ++ if (this.isShown && this.options.backdrop) { ++ var doAnimate = $.support.transition && animate ++ ++ this.$backdrop = $(document.createElement('div')) ++ .addClass('modal-backdrop ' + animate) ++ .appendTo(this.$body) ++ ++ this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) { ++ if (this.ignoreBackdropClick) { ++ this.ignoreBackdropClick = false ++ return ++ } ++ if (e.target !== e.currentTarget) return ++ this.options.backdrop == 'static' ++ ? this.$element[0].focus() ++ : this.hide() ++ }, this)) ++ ++ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow ++ ++ this.$backdrop.addClass('in') ++ ++ if (!callback) return ++ ++ doAnimate ? ++ this.$backdrop ++ .one('bsTransitionEnd', callback) ++ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : ++ callback() ++ ++ } else if (!this.isShown && this.$backdrop) { ++ this.$backdrop.removeClass('in') ++ ++ var callbackRemove = function () { ++ that.removeBackdrop() ++ callback && callback() ++ } ++ $.support.transition && this.$element.hasClass('fade') ? ++ this.$backdrop ++ .one('bsTransitionEnd', callbackRemove) ++ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : ++ callbackRemove() ++ ++ } else if (callback) { ++ callback() ++ } ++ } ++ ++ // these following methods are used to handle overflowing modals ++ ++ Modal.prototype.handleUpdate = function () { ++ this.adjustDialog() ++ } ++ ++ Modal.prototype.adjustDialog = function () { ++ var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight ++ ++ this.$element.css({ ++ paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '', ++ paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : '' ++ }) ++ } ++ ++ Modal.prototype.resetAdjustments = function () { ++ this.$element.css({ ++ paddingLeft: '', ++ paddingRight: '' ++ }) ++ } ++ ++ Modal.prototype.checkScrollbar = function () { ++ var fullWindowWidth = window.innerWidth ++ if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8 ++ var documentElementRect = document.documentElement.getBoundingClientRect() ++ fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left) ++ } ++ this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth ++ this.scrollbarWidth = this.measureScrollbar() ++ } ++ ++ Modal.prototype.setScrollbar = function () { ++ var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10) ++ this.originalBodyPad = document.body.style.paddingRight || '' ++ if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth) ++ } ++ ++ Modal.prototype.resetScrollbar = function () { ++ this.$body.css('padding-right', this.originalBodyPad) ++ } ++ ++ Modal.prototype.measureScrollbar = function () { // thx walsh ++ var scrollDiv = document.createElement('div') ++ scrollDiv.className = 'modal-scrollbar-measure' ++ this.$body.append(scrollDiv) ++ var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth ++ this.$body[0].removeChild(scrollDiv) ++ return scrollbarWidth ++ } ++ ++ ++ // MODAL PLUGIN DEFINITION ++ // ======================= ++ ++ function Plugin(option, _relatedTarget) { ++ return this.each(function () { ++ var $this = $(this) ++ var data = $this.data('bs.modal') ++ var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) ++ ++ if (!data) $this.data('bs.modal', (data = new Modal(this, options))) ++ if (typeof option == 'string') data[option](_relatedTarget) ++ else if (options.show) data.show(_relatedTarget) ++ }) ++ } ++ ++ var old = $.fn.modal ++ ++ $.fn.modal = Plugin ++ $.fn.modal.Constructor = Modal ++ ++ ++ // MODAL NO CONFLICT ++ // ================= ++ ++ $.fn.modal.noConflict = function () { ++ $.fn.modal = old ++ return this ++ } ++ ++ ++ // MODAL DATA-API ++ // ============== ++ ++ $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { ++ var $this = $(this) ++ var href = $this.attr('href') ++ var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7 ++ var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) ++ ++ if ($this.is('a')) e.preventDefault() ++ ++ $target.one('show.bs.modal', function (showEvent) { ++ if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown ++ $target.one('hidden.bs.modal', function () { ++ $this.is(':visible') && $this.trigger('focus') ++ }) ++ }) ++ Plugin.call($target, option, this) ++ }) ++ ++}(jQuery); ++ ++/* ======================================================================== ++ * Bootstrap: tooltip.js v3.3.7 ++ * http://getbootstrap.com/javascript/#tooltip ++ * Inspired by the original jQuery.tipsy by Jason Frame ++ * ======================================================================== ++ * Copyright 2011-2016 Twitter, Inc. ++ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) ++ * ======================================================================== */ ++ ++ +++function ($) { ++ 'use strict'; ++ ++ // TOOLTIP PUBLIC CLASS DEFINITION ++ // =============================== ++ ++ var Tooltip = function (element, options) { ++ this.type = null ++ this.options = null ++ this.enabled = null ++ this.timeout = null ++ this.hoverState = null ++ this.$element = null ++ this.inState = null ++ ++ this.init('tooltip', element, options) ++ } ++ ++ Tooltip.VERSION = '3.3.7' ++ ++ Tooltip.TRANSITION_DURATION = 150 ++ ++ Tooltip.DEFAULTS = { ++ animation: true, ++ placement: 'top', ++ selector: false, ++ template: '', ++ trigger: 'hover focus', ++ title: '', ++ delay: 0, ++ html: false, ++ container: false, ++ viewport: { ++ selector: 'body', ++ padding: 0 ++ } ++ } ++ ++ Tooltip.prototype.init = function (type, element, options) { ++ this.enabled = true ++ this.type = type ++ this.$element = $(element) ++ this.options = this.getOptions(options) ++ this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport)) ++ this.inState = { click: false, hover: false, focus: false } ++ ++ if (this.$element[0] instanceof document.constructor && !this.options.selector) { ++ throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!') ++ } ++ ++ var triggers = this.options.trigger.split(' ') ++ ++ for (var i = triggers.length; i--;) { ++ var trigger = triggers[i] ++ ++ if (trigger == 'click') { ++ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) ++ } else if (trigger != 'manual') { ++ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' ++ var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' ++ ++ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) ++ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) ++ } ++ } ++ ++ this.options.selector ? ++ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : ++ this.fixTitle() ++ } ++ ++ Tooltip.prototype.getDefaults = function () { ++ return Tooltip.DEFAULTS ++ } ++ ++ Tooltip.prototype.getOptions = function (options) { ++ options = $.extend({}, this.getDefaults(), this.$element.data(), options) ++ ++ if (options.delay && typeof options.delay == 'number') { ++ options.delay = { ++ show: options.delay, ++ hide: options.delay ++ } ++ } ++ ++ return options ++ } ++ ++ Tooltip.prototype.getDelegateOptions = function () { ++ var options = {} ++ var defaults = this.getDefaults() ++ ++ this._options && $.each(this._options, function (key, value) { ++ if (defaults[key] != value) options[key] = value ++ }) ++ ++ return options ++ } ++ ++ Tooltip.prototype.enter = function (obj) { ++ var self = obj instanceof this.constructor ? ++ obj : $(obj.currentTarget).data('bs.' + this.type) ++ ++ if (!self) { ++ self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) ++ $(obj.currentTarget).data('bs.' + this.type, self) ++ } ++ ++ if (obj instanceof $.Event) { ++ self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true ++ } ++ ++ if (self.tip().hasClass('in') || self.hoverState == 'in') { ++ self.hoverState = 'in' ++ return ++ } ++ ++ clearTimeout(self.timeout) ++ ++ self.hoverState = 'in' ++ ++ if (!self.options.delay || !self.options.delay.show) return self.show() ++ ++ self.timeout = setTimeout(function () { ++ if (self.hoverState == 'in') self.show() ++ }, self.options.delay.show) ++ } ++ ++ Tooltip.prototype.isInStateTrue = function () { ++ for (var key in this.inState) { ++ if (this.inState[key]) return true ++ } ++ ++ return false ++ } ++ ++ Tooltip.prototype.leave = function (obj) { ++ var self = obj instanceof this.constructor ? ++ obj : $(obj.currentTarget).data('bs.' + this.type) ++ ++ if (!self) { ++ self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) ++ $(obj.currentTarget).data('bs.' + this.type, self) ++ } ++ ++ if (obj instanceof $.Event) { ++ self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false ++ } ++ ++ if (self.isInStateTrue()) return ++ ++ clearTimeout(self.timeout) ++ ++ self.hoverState = 'out' ++ ++ if (!self.options.delay || !self.options.delay.hide) return self.hide() ++ ++ self.timeout = setTimeout(function () { ++ if (self.hoverState == 'out') self.hide() ++ }, self.options.delay.hide) ++ } ++ ++ Tooltip.prototype.show = function () { ++ var e = $.Event('show.bs.' + this.type) ++ ++ if (this.hasContent() && this.enabled) { ++ this.$element.trigger(e) ++ ++ var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]) ++ if (e.isDefaultPrevented() || !inDom) return ++ var that = this ++ ++ var $tip = this.tip() ++ ++ var tipId = this.getUID(this.type) ++ ++ this.setContent() ++ $tip.attr('id', tipId) ++ this.$element.attr('aria-describedby', tipId) ++ ++ if (this.options.animation) $tip.addClass('fade') ++ ++ var placement = typeof this.options.placement == 'function' ? ++ this.options.placement.call(this, $tip[0], this.$element[0]) : ++ this.options.placement ++ ++ var autoToken = /\s?auto?\s?/i ++ var autoPlace = autoToken.test(placement) ++ if (autoPlace) placement = placement.replace(autoToken, '') || 'top' ++ ++ $tip ++ .detach() ++ .css({ top: 0, left: 0, display: 'block' }) ++ .addClass(placement) ++ .data('bs.' + this.type, this) ++ ++ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) ++ this.$element.trigger('inserted.bs.' + this.type) ++ ++ var pos = this.getPosition() ++ var actualWidth = $tip[0].offsetWidth ++ var actualHeight = $tip[0].offsetHeight ++ ++ if (autoPlace) { ++ var orgPlacement = placement ++ var viewportDim = this.getPosition(this.$viewport) ++ ++ placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' : ++ placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' : ++ placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' : ++ placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' : ++ placement ++ ++ $tip ++ .removeClass(orgPlacement) ++ .addClass(placement) ++ } ++ ++ var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) ++ ++ this.applyPlacement(calculatedOffset, placement) ++ ++ var complete = function () { ++ var prevHoverState = that.hoverState ++ that.$element.trigger('shown.bs.' + that.type) ++ that.hoverState = null ++ ++ if (prevHoverState == 'out') that.leave(that) ++ } ++ ++ $.support.transition && this.$tip.hasClass('fade') ? ++ $tip ++ .one('bsTransitionEnd', complete) ++ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : ++ complete() ++ } ++ } ++ ++ Tooltip.prototype.applyPlacement = function (offset, placement) { ++ var $tip = this.tip() ++ var width = $tip[0].offsetWidth ++ var height = $tip[0].offsetHeight ++ ++ // manually read margins because getBoundingClientRect includes difference ++ var marginTop = parseInt($tip.css('margin-top'), 10) ++ var marginLeft = parseInt($tip.css('margin-left'), 10) ++ ++ // we must check for NaN for ie 8/9 ++ if (isNaN(marginTop)) marginTop = 0 ++ if (isNaN(marginLeft)) marginLeft = 0 ++ ++ offset.top += marginTop ++ offset.left += marginLeft ++ ++ // $.fn.offset doesn't round pixel values ++ // so we use setOffset directly with our own function B-0 ++ $.offset.setOffset($tip[0], $.extend({ ++ using: function (props) { ++ $tip.css({ ++ top: Math.round(props.top), ++ left: Math.round(props.left) ++ }) ++ } ++ }, offset), 0) ++ ++ $tip.addClass('in') ++ ++ // check to see if placing tip in new offset caused the tip to resize itself ++ var actualWidth = $tip[0].offsetWidth ++ var actualHeight = $tip[0].offsetHeight ++ ++ if (placement == 'top' && actualHeight != height) { ++ offset.top = offset.top + height - actualHeight ++ } ++ ++ var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) ++ ++ if (delta.left) offset.left += delta.left ++ else offset.top += delta.top ++ ++ var isVertical = /top|bottom/.test(placement) ++ var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight ++ var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight' ++ ++ $tip.offset(offset) ++ this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical) ++ } ++ ++ Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) { ++ this.arrow() ++ .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%') ++ .css(isVertical ? 'top' : 'left', '') ++ } ++ ++ Tooltip.prototype.setContent = function () { ++ var $tip = this.tip() ++ var title = this.getTitle() ++ ++ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) ++ $tip.removeClass('fade in top bottom left right') ++ } ++ ++ Tooltip.prototype.hide = function (callback) { ++ var that = this ++ var $tip = $(this.$tip) ++ var e = $.Event('hide.bs.' + this.type) ++ ++ function complete() { ++ if (that.hoverState != 'in') $tip.detach() ++ if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary. ++ that.$element ++ .removeAttr('aria-describedby') ++ .trigger('hidden.bs.' + that.type) ++ } ++ callback && callback() ++ } ++ ++ this.$element.trigger(e) ++ ++ if (e.isDefaultPrevented()) return ++ ++ $tip.removeClass('in') ++ ++ $.support.transition && $tip.hasClass('fade') ? ++ $tip ++ .one('bsTransitionEnd', complete) ++ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : ++ complete() ++ ++ this.hoverState = null ++ ++ return this ++ } ++ ++ Tooltip.prototype.fixTitle = function () { ++ var $e = this.$element ++ if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') { ++ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') ++ } ++ } ++ ++ Tooltip.prototype.hasContent = function () { ++ return this.getTitle() ++ } ++ ++ Tooltip.prototype.getPosition = function ($element) { ++ $element = $element || this.$element ++ ++ var el = $element[0] ++ var isBody = el.tagName == 'BODY' ++ ++ var elRect = el.getBoundingClientRect() ++ if (elRect.width == null) { ++ // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 ++ elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }) ++ } ++ var isSvg = window.SVGElement && el instanceof window.SVGElement ++ // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3. ++ // See https://github.com/twbs/bootstrap/issues/20280 ++ var elOffset = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset()) ++ var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() } ++ var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null ++ ++ return $.extend({}, elRect, scroll, outerDims, elOffset) ++ } ++ ++ Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { ++ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : ++ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : ++ placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : ++ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } ++ ++ } ++ ++ Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { ++ var delta = { top: 0, left: 0 } ++ if (!this.$viewport) return delta ++ ++ var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 ++ var viewportDimensions = this.getPosition(this.$viewport) ++ ++ if (/right|left/.test(placement)) { ++ var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll ++ var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight ++ if (topEdgeOffset < viewportDimensions.top) { // top overflow ++ delta.top = viewportDimensions.top - topEdgeOffset ++ } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow ++ delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset ++ } ++ } else { ++ var leftEdgeOffset = pos.left - viewportPadding ++ var rightEdgeOffset = pos.left + viewportPadding + actualWidth ++ if (leftEdgeOffset < viewportDimensions.left) { // left overflow ++ delta.left = viewportDimensions.left - leftEdgeOffset ++ } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow ++ delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset ++ } ++ } ++ ++ return delta ++ } ++ ++ Tooltip.prototype.getTitle = function () { ++ var title ++ var $e = this.$element ++ var o = this.options ++ ++ title = $e.attr('data-original-title') ++ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) ++ ++ return title ++ } ++ ++ Tooltip.prototype.getUID = function (prefix) { ++ do prefix += ~~(Math.random() * 1000000) ++ while (document.getElementById(prefix)) ++ return prefix ++ } ++ ++ Tooltip.prototype.tip = function () { ++ if (!this.$tip) { ++ this.$tip = $(this.options.template) ++ if (this.$tip.length != 1) { ++ throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!') ++ } ++ } ++ return this.$tip ++ } ++ ++ Tooltip.prototype.arrow = function () { ++ return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')) ++ } ++ ++ Tooltip.prototype.enable = function () { ++ this.enabled = true ++ } ++ ++ Tooltip.prototype.disable = function () { ++ this.enabled = false ++ } ++ ++ Tooltip.prototype.toggleEnabled = function () { ++ this.enabled = !this.enabled ++ } ++ ++ Tooltip.prototype.toggle = function (e) { ++ var self = this ++ if (e) { ++ self = $(e.currentTarget).data('bs.' + this.type) ++ if (!self) { ++ self = new this.constructor(e.currentTarget, this.getDelegateOptions()) ++ $(e.currentTarget).data('bs.' + this.type, self) ++ } ++ } ++ ++ if (e) { ++ self.inState.click = !self.inState.click ++ if (self.isInStateTrue()) self.enter(self) ++ else self.leave(self) ++ } else { ++ self.tip().hasClass('in') ? self.leave(self) : self.enter(self) ++ } ++ } ++ ++ Tooltip.prototype.destroy = function () { ++ var that = this ++ clearTimeout(this.timeout) ++ this.hide(function () { ++ that.$element.off('.' + that.type).removeData('bs.' + that.type) ++ if (that.$tip) { ++ that.$tip.detach() ++ } ++ that.$tip = null ++ that.$arrow = null ++ that.$viewport = null ++ that.$element = null ++ }) ++ } ++ ++ ++ // TOOLTIP PLUGIN DEFINITION ++ // ========================= ++ ++ function Plugin(option) { ++ return this.each(function () { ++ var $this = $(this) ++ var data = $this.data('bs.tooltip') ++ var options = typeof option == 'object' && option ++ ++ if (!data && /destroy|hide/.test(option)) return ++ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) ++ if (typeof option == 'string') data[option]() ++ }) ++ } ++ ++ var old = $.fn.tooltip ++ ++ $.fn.tooltip = Plugin ++ $.fn.tooltip.Constructor = Tooltip ++ ++ ++ // TOOLTIP NO CONFLICT ++ // =================== ++ ++ $.fn.tooltip.noConflict = function () { ++ $.fn.tooltip = old ++ return this ++ } ++ ++}(jQuery); ++ ++/* ======================================================================== ++ * Bootstrap: popover.js v3.3.7 ++ * http://getbootstrap.com/javascript/#popovers ++ * ======================================================================== ++ * Copyright 2011-2016 Twitter, Inc. ++ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) ++ * ======================================================================== */ ++ ++ +++function ($) { ++ 'use strict'; ++ ++ // POPOVER PUBLIC CLASS DEFINITION ++ // =============================== ++ ++ var Popover = function (element, options) { ++ this.init('popover', element, options) ++ } ++ ++ if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') ++ ++ Popover.VERSION = '3.3.7' ++ ++ Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { ++ placement: 'right', ++ trigger: 'click', ++ content: '', ++ template: '' ++ }) ++ ++ ++ // NOTE: POPOVER EXTENDS tooltip.js ++ // ================================ ++ ++ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) ++ ++ Popover.prototype.constructor = Popover ++ ++ Popover.prototype.getDefaults = function () { ++ return Popover.DEFAULTS ++ } ++ ++ Popover.prototype.setContent = function () { ++ var $tip = this.tip() ++ var title = this.getTitle() ++ var content = this.getContent() ++ ++ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) ++ $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events ++ this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' ++ ](content) ++ ++ $tip.removeClass('fade top bottom left right in') ++ ++ // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do ++ // this manually by checking the contents. ++ if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() ++ } ++ ++ Popover.prototype.hasContent = function () { ++ return this.getTitle() || this.getContent() ++ } ++ ++ Popover.prototype.getContent = function () { ++ var $e = this.$element ++ var o = this.options ++ ++ return $e.attr('data-content') ++ || (typeof o.content == 'function' ? ++ o.content.call($e[0]) : ++ o.content) ++ } ++ ++ Popover.prototype.arrow = function () { ++ return (this.$arrow = this.$arrow || this.tip().find('.arrow')) ++ } ++ ++ ++ // POPOVER PLUGIN DEFINITION ++ // ========================= ++ ++ function Plugin(option) { ++ return this.each(function () { ++ var $this = $(this) ++ var data = $this.data('bs.popover') ++ var options = typeof option == 'object' && option ++ ++ if (!data && /destroy|hide/.test(option)) return ++ if (!data) $this.data('bs.popover', (data = new Popover(this, options))) ++ if (typeof option == 'string') data[option]() ++ }) ++ } ++ ++ var old = $.fn.popover ++ ++ $.fn.popover = Plugin ++ $.fn.popover.Constructor = Popover ++ ++ ++ // POPOVER NO CONFLICT ++ // =================== ++ ++ $.fn.popover.noConflict = function () { ++ $.fn.popover = old ++ return this ++ } ++ ++}(jQuery); ++ ++/* ======================================================================== ++ * Bootstrap: scrollspy.js v3.3.7 ++ * http://getbootstrap.com/javascript/#scrollspy ++ * ======================================================================== ++ * Copyright 2011-2016 Twitter, Inc. ++ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) ++ * ======================================================================== */ ++ ++ +++function ($) { ++ 'use strict'; ++ ++ // SCROLLSPY CLASS DEFINITION ++ // ========================== ++ ++ function ScrollSpy(element, options) { ++ this.$body = $(document.body) ++ this.$scrollElement = $(element).is(document.body) ? $(window) : $(element) ++ this.options = $.extend({}, ScrollSpy.DEFAULTS, options) ++ this.selector = (this.options.target || '') + ' .nav li > a' ++ this.offsets = [] ++ this.targets = [] ++ this.activeTarget = null ++ this.scrollHeight = 0 ++ ++ this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this)) ++ this.refresh() ++ this.process() ++ } ++ ++ ScrollSpy.VERSION = '3.3.7' ++ ++ ScrollSpy.DEFAULTS = { ++ offset: 10 ++ } ++ ++ ScrollSpy.prototype.getScrollHeight = function () { ++ return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight) ++ } ++ ++ ScrollSpy.prototype.refresh = function () { ++ var that = this ++ var offsetMethod = 'offset' ++ var offsetBase = 0 ++ ++ this.offsets = [] ++ this.targets = [] ++ this.scrollHeight = this.getScrollHeight() ++ ++ if (!$.isWindow(this.$scrollElement[0])) { ++ offsetMethod = 'position' ++ offsetBase = this.$scrollElement.scrollTop() ++ } ++ ++ this.$body ++ .find(this.selector) ++ .map(function () { ++ var $el = $(this) ++ var href = $el.data('target') || $el.attr('href') ++ var $href = /^#./.test(href) && $(href) ++ ++ return ($href ++ && $href.length ++ && $href.is(':visible') ++ && [[$href[offsetMethod]().top + offsetBase, href]]) || null ++ }) ++ .sort(function (a, b) { return a[0] - b[0] }) ++ .each(function () { ++ that.offsets.push(this[0]) ++ that.targets.push(this[1]) ++ }) ++ } ++ ++ ScrollSpy.prototype.process = function () { ++ var scrollTop = this.$scrollElement.scrollTop() + this.options.offset ++ var scrollHeight = this.getScrollHeight() ++ var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height() ++ var offsets = this.offsets ++ var targets = this.targets ++ var activeTarget = this.activeTarget ++ var i ++ ++ if (this.scrollHeight != scrollHeight) { ++ this.refresh() ++ } ++ ++ if (scrollTop >= maxScroll) { ++ return activeTarget != (i = targets[targets.length - 1]) && this.activate(i) ++ } ++ ++ if (activeTarget && scrollTop < offsets[0]) { ++ this.activeTarget = null ++ return this.clear() ++ } ++ ++ for (i = offsets.length; i--;) { ++ activeTarget != targets[i] ++ && scrollTop >= offsets[i] ++ && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1]) ++ && this.activate(targets[i]) ++ } ++ } ++ ++ ScrollSpy.prototype.activate = function (target) { ++ this.activeTarget = target ++ ++ this.clear() ++ ++ var selector = this.selector + ++ '[data-target="' + target + '"],' + ++ this.selector + '[href="' + target + '"]' ++ ++ var active = $(selector) ++ .parents('li') ++ .addClass('active') ++ ++ if (active.parent('.dropdown-menu').length) { ++ active = active ++ .closest('li.dropdown') ++ .addClass('active') ++ } ++ ++ active.trigger('activate.bs.scrollspy') ++ } ++ ++ ScrollSpy.prototype.clear = function () { ++ $(this.selector) ++ .parentsUntil(this.options.target, '.active') ++ .removeClass('active') ++ } ++ ++ ++ // SCROLLSPY PLUGIN DEFINITION ++ // =========================== ++ ++ function Plugin(option) { ++ return this.each(function () { ++ var $this = $(this) ++ var data = $this.data('bs.scrollspy') ++ var options = typeof option == 'object' && option ++ ++ if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options))) ++ if (typeof option == 'string') data[option]() ++ }) ++ } ++ ++ var old = $.fn.scrollspy ++ ++ $.fn.scrollspy = Plugin ++ $.fn.scrollspy.Constructor = ScrollSpy ++ ++ ++ // SCROLLSPY NO CONFLICT ++ // ===================== ++ ++ $.fn.scrollspy.noConflict = function () { ++ $.fn.scrollspy = old ++ return this ++ } ++ ++ ++ // SCROLLSPY DATA-API ++ // ================== ++ ++ $(window).on('load.bs.scrollspy.data-api', function () { ++ $('[data-spy="scroll"]').each(function () { ++ var $spy = $(this) ++ Plugin.call($spy, $spy.data()) ++ }) ++ }) ++ ++}(jQuery); ++ ++/* ======================================================================== ++ * Bootstrap: tab.js v3.3.7 ++ * http://getbootstrap.com/javascript/#tabs ++ * ======================================================================== ++ * Copyright 2011-2016 Twitter, Inc. ++ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) ++ * ======================================================================== */ ++ ++ +++function ($) { ++ 'use strict'; ++ ++ // TAB CLASS DEFINITION ++ // ==================== ++ ++ var Tab = function (element) { ++ // jscs:disable requireDollarBeforejQueryAssignment ++ this.element = $(element) ++ // jscs:enable requireDollarBeforejQueryAssignment ++ } ++ ++ Tab.VERSION = '3.3.7' ++ ++ Tab.TRANSITION_DURATION = 150 ++ ++ Tab.prototype.show = function () { ++ var $this = this.element ++ var $ul = $this.closest('ul:not(.dropdown-menu)') ++ var selector = $this.data('target') ++ ++ if (!selector) { ++ selector = $this.attr('href') ++ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 ++ } ++ ++ if ($this.parent('li').hasClass('active')) return ++ ++ var $previous = $ul.find('.active:last a') ++ var hideEvent = $.Event('hide.bs.tab', { ++ relatedTarget: $this[0] ++ }) ++ var showEvent = $.Event('show.bs.tab', { ++ relatedTarget: $previous[0] ++ }) ++ ++ $previous.trigger(hideEvent) ++ $this.trigger(showEvent) ++ ++ if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return ++ ++ var $target = $(selector) ++ ++ this.activate($this.closest('li'), $ul) ++ this.activate($target, $target.parent(), function () { ++ $previous.trigger({ ++ type: 'hidden.bs.tab', ++ relatedTarget: $this[0] ++ }) ++ $this.trigger({ ++ type: 'shown.bs.tab', ++ relatedTarget: $previous[0] ++ }) ++ }) ++ } ++ ++ Tab.prototype.activate = function (element, container, callback) { ++ var $active = container.find('> .active') ++ var transition = callback ++ && $.support.transition ++ && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length) ++ ++ function next() { ++ $active ++ .removeClass('active') ++ .find('> .dropdown-menu > .active') ++ .removeClass('active') ++ .end() ++ .find('[data-toggle="tab"]') ++ .attr('aria-expanded', false) ++ ++ element ++ .addClass('active') ++ .find('[data-toggle="tab"]') ++ .attr('aria-expanded', true) ++ ++ if (transition) { ++ element[0].offsetWidth // reflow for transition ++ element.addClass('in') ++ } else { ++ element.removeClass('fade') ++ } ++ ++ if (element.parent('.dropdown-menu').length) { ++ element ++ .closest('li.dropdown') ++ .addClass('active') ++ .end() ++ .find('[data-toggle="tab"]') ++ .attr('aria-expanded', true) ++ } ++ ++ callback && callback() ++ } ++ ++ $active.length && transition ? ++ $active ++ .one('bsTransitionEnd', next) ++ .emulateTransitionEnd(Tab.TRANSITION_DURATION) : ++ next() ++ ++ $active.removeClass('in') ++ } ++ ++ ++ // TAB PLUGIN DEFINITION ++ // ===================== ++ ++ function Plugin(option) { ++ return this.each(function () { ++ var $this = $(this) ++ var data = $this.data('bs.tab') ++ ++ if (!data) $this.data('bs.tab', (data = new Tab(this))) ++ if (typeof option == 'string') data[option]() ++ }) ++ } ++ ++ var old = $.fn.tab ++ ++ $.fn.tab = Plugin ++ $.fn.tab.Constructor = Tab ++ ++ ++ // TAB NO CONFLICT ++ // =============== ++ ++ $.fn.tab.noConflict = function () { ++ $.fn.tab = old ++ return this ++ } ++ ++ ++ // TAB DATA-API ++ // ============ ++ ++ var clickHandler = function (e) { ++ e.preventDefault() ++ Plugin.call($(this), 'show') ++ } ++ ++ $(document) ++ .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler) ++ .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler) ++ ++}(jQuery); ++ ++/* ======================================================================== ++ * Bootstrap: affix.js v3.3.7 ++ * http://getbootstrap.com/javascript/#affix ++ * ======================================================================== ++ * Copyright 2011-2016 Twitter, Inc. ++ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) ++ * ======================================================================== */ ++ ++ +++function ($) { ++ 'use strict'; ++ ++ // AFFIX CLASS DEFINITION ++ // ====================== ++ ++ var Affix = function (element, options) { ++ this.options = $.extend({}, Affix.DEFAULTS, options) ++ ++ this.$target = $(this.options.target) ++ .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) ++ .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) ++ ++ this.$element = $(element) ++ this.affixed = null ++ this.unpin = null ++ this.pinnedOffset = null ++ ++ this.checkPosition() ++ } ++ ++ Affix.VERSION = '3.3.7' ++ ++ Affix.RESET = 'affix affix-top affix-bottom' ++ ++ Affix.DEFAULTS = { ++ offset: 0, ++ target: window ++ } ++ ++ Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) { ++ var scrollTop = this.$target.scrollTop() ++ var position = this.$element.offset() ++ var targetHeight = this.$target.height() ++ ++ if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false ++ ++ if (this.affixed == 'bottom') { ++ if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom' ++ return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom' ++ } ++ ++ var initializing = this.affixed == null ++ var colliderTop = initializing ? scrollTop : position.top ++ var colliderHeight = initializing ? targetHeight : height ++ ++ if (offsetTop != null && scrollTop <= offsetTop) return 'top' ++ if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom' ++ ++ return false ++ } ++ ++ Affix.prototype.getPinnedOffset = function () { ++ if (this.pinnedOffset) return this.pinnedOffset ++ this.$element.removeClass(Affix.RESET).addClass('affix') ++ var scrollTop = this.$target.scrollTop() ++ var position = this.$element.offset() ++ return (this.pinnedOffset = position.top - scrollTop) ++ } ++ ++ Affix.prototype.checkPositionWithEventLoop = function () { ++ setTimeout($.proxy(this.checkPosition, this), 1) ++ } ++ ++ Affix.prototype.checkPosition = function () { ++ if (!this.$element.is(':visible')) return ++ ++ var height = this.$element.height() ++ var offset = this.options.offset ++ var offsetTop = offset.top ++ var offsetBottom = offset.bottom ++ var scrollHeight = Math.max($(document).height(), $(document.body).height()) ++ ++ if (typeof offset != 'object') offsetBottom = offsetTop = offset ++ if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) ++ if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) ++ ++ var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom) ++ ++ if (this.affixed != affix) { ++ if (this.unpin != null) this.$element.css('top', '') ++ ++ var affixType = 'affix' + (affix ? '-' + affix : '') ++ var e = $.Event(affixType + '.bs.affix') ++ ++ this.$element.trigger(e) ++ ++ if (e.isDefaultPrevented()) return ++ ++ this.affixed = affix ++ this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null ++ ++ this.$element ++ .removeClass(Affix.RESET) ++ .addClass(affixType) ++ .trigger(affixType.replace('affix', 'affixed') + '.bs.affix') ++ } ++ ++ if (affix == 'bottom') { ++ this.$element.offset({ ++ top: scrollHeight - height - offsetBottom ++ }) ++ } ++ } ++ ++ ++ // AFFIX PLUGIN DEFINITION ++ // ======================= ++ ++ function Plugin(option) { ++ return this.each(function () { ++ var $this = $(this) ++ var data = $this.data('bs.affix') ++ var options = typeof option == 'object' && option ++ ++ if (!data) $this.data('bs.affix', (data = new Affix(this, options))) ++ if (typeof option == 'string') data[option]() ++ }) ++ } ++ ++ var old = $.fn.affix ++ ++ $.fn.affix = Plugin ++ $.fn.affix.Constructor = Affix ++ ++ ++ // AFFIX NO CONFLICT ++ // ================= ++ ++ $.fn.affix.noConflict = function () { ++ $.fn.affix = old ++ return this ++ } ++ ++ ++ // AFFIX DATA-API ++ // ============== ++ ++ $(window).on('load', function () { ++ $('[data-spy="affix"]').each(function () { ++ var $spy = $(this) ++ var data = $spy.data() ++ ++ data.offset = data.offset || {} ++ ++ if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom ++ if (data.offsetTop != null) data.offset.top = data.offsetTop ++ ++ Plugin.call($spy, data) ++ }) ++ }) ++ ++}(jQuery); diff --cc debian/missing-sources/two.js index 000000000,000000000..859d3b418 new file mode 100644 --- /dev/null +++ b/debian/missing-sources/two.js @@@ -1,0 -1,0 +1,10244 @@@ ++/** ++ * two.js ++ * a two-dimensional drawing api meant for modern browsers. It is renderer ++ * agnostic enabling the same api for rendering in multiple contexts: webgl, ++ * canvas2d, and svg. ++ * ++ * Copyright (c) 2012 - 2017 jonobr1 / http://jonobr1.com ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ * ++ */ ++ ++this.Two = (function(previousTwo) { ++ ++ var root = typeof window != 'undefined' ? window : typeof global != 'undefined' ? global : null; ++ var toString = Object.prototype.toString; ++ var _ = { ++ // http://underscorejs.org/ • 1.8.3 ++ _indexAmount: 0, ++ natural: { ++ slice: Array.prototype.slice, ++ indexOf: Array.prototype.indexOf, ++ keys: Object.keys, ++ bind: Function.prototype.bind, ++ create: Object.create ++ }, ++ identity: function(value) { ++ return value; ++ }, ++ isArguments: function(obj) { ++ return toString.call(obj) === '[object Arguments]'; ++ }, ++ isFunction: function(obj) { ++ return toString.call(obj) === '[object Function]'; ++ }, ++ isString: function(obj) { ++ return toString.call(obj) === '[object String]'; ++ }, ++ isNumber: function(obj) { ++ return toString.call(obj) === '[object Number]'; ++ }, ++ isDate: function(obj) { ++ return toString.call(obj) === '[object Date]'; ++ }, ++ isRegExp: function(obj) { ++ return toString.call(obj) === '[object RegExp]'; ++ }, ++ isError: function(obj) { ++ return toString.call(obj) === '[object Error]'; ++ }, ++ isFinite: function(obj) { ++ return isFinite(obj) && !isNaN(parseFloat(obj)); ++ }, ++ isNaN: function(obj) { ++ return _.isNumber(obj) && obj !== +obj; ++ }, ++ isBoolean: function(obj) { ++ return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; ++ }, ++ isNull: function(obj) { ++ return obj === null; ++ }, ++ isUndefined: function(obj) { ++ return obj === void 0; ++ }, ++ isEmpty: function(obj) { ++ if (obj == null) return true; ++ if (isArrayLike && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; ++ return _.keys(obj).length === 0; ++ }, ++ isElement: function(obj) { ++ return !!(obj && obj.nodeType === 1); ++ }, ++ isArray: Array.isArray || function(obj) { ++ return toString.call(obj) === '[object Array]'; ++ }, ++ isObject: function(obj) { ++ var type = typeof obj; ++ return type === 'function' || type === 'object' && !!obj; ++ }, ++ toArray: function(obj) { ++ if (!obj) { ++ return []; ++ } ++ if (_.isArray(obj)) { ++ return slice.call(obj); ++ } ++ if (isArrayLike(obj)) { ++ return _.map(obj, _.identity); ++ } ++ return _.values(obj); ++ }, ++ range: function(start, stop, step) { ++ if (stop == null) { ++ stop = start || 0; ++ start = 0; ++ } ++ step = step || 1; ++ ++ var length = Math.max(Math.ceil((stop - start) / step), 0); ++ var range = Array(length); ++ ++ for (var idx = 0; idx < length; idx++, start += step) { ++ range[idx] = start; ++ } ++ ++ return range; ++ }, ++ indexOf: function(list, item) { ++ if (!!_.natural.indexOf) { ++ return _.natural.indexOf.call(list, item); ++ } ++ for (var i = 0; i < list.length; i++) { ++ if (list[i] === item) { ++ return i; ++ } ++ } ++ return -1; ++ }, ++ has: function(obj, key) { ++ return obj != null && hasOwnProperty.call(obj, key); ++ }, ++ bind: function(func, ctx) { ++ var natural = _.natural.bind; ++ if (natural && func.bind === natural) { ++ return natural.apply(func, slice.call(arguments, 1)); ++ } ++ var args = slice.call(arguments, 2); ++ return function() { ++ func.apply(ctx, args); ++ }; ++ }, ++ extend: function(base) { ++ var sources = slice.call(arguments, 1); ++ for (var i = 0; i < sources.length; i++) { ++ var obj = sources[i]; ++ for (var k in obj) { ++ base[k] = obj[k]; ++ } ++ } ++ return base; ++ }, ++ defaults: function(base) { ++ var sources = slice.call(arguments, 1); ++ for (var i = 0; i < sources.length; i++) { ++ var obj = sources[i]; ++ for (var k in obj) { ++ if (base[k] === void 0) { ++ base[k] = obj[k]; ++ } ++ } ++ } ++ return base; ++ }, ++ keys: function(obj) { ++ if (!_.isObject(obj)) { ++ return []; ++ } ++ if (_.natural.keys) { ++ return _.natural.keys(obj); ++ } ++ var keys = []; ++ for (var k in obj) { ++ if (_.has(obj, k)) { ++ keys.push(k); ++ } ++ } ++ return keys; ++ }, ++ values: function(obj) { ++ var keys = _.keys(obj); ++ var values = []; ++ for (var i = 0; i < keys.length; i++) { ++ var k = keys[i]; ++ values.push(obj[k]); ++ } ++ return values; ++ }, ++ each: function(obj, iteratee, context) { ++ var ctx = context || this; ++ var keys = !isArrayLike(obj) && _.keys(obj); ++ var length = (keys || obj).length; ++ for (var i = 0; i < length; i++) { ++ var k = keys ? keys[i] : i; ++ iteratee.call(ctx, obj[k], k, obj); ++ } ++ return obj; ++ }, ++ map: function(obj, iteratee, context) { ++ var ctx = context || this; ++ var keys = !isArrayLike(obj) && _.keys(obj); ++ var length = (keys || obj).length; ++ var result = []; ++ for (var i = 0; i < length; i++) { ++ var k = keys ? keys[i] : i; ++ result[i] = iteratee.call(ctx, obj[k], k, obj); ++ } ++ return result; ++ }, ++ once: function(func) { ++ var init = false; ++ return function() { ++ if (!!init) { ++ return func; ++ } ++ init = true; ++ return func.apply(this, arguments); ++ } ++ }, ++ after: function(times, func) { ++ return function() { ++ while (--times < 1) { ++ return func.apply(this, arguments); ++ } ++ } ++ }, ++ uniqueId: function(prefix) { ++ var id = ++_._indexAmount + ''; ++ return prefix ? prefix + id : id; ++ } ++ }; ++ ++ /** ++ * Constants ++ */ ++ ++ var sin = Math.sin, ++ cos = Math.cos, ++ atan2 = Math.atan2, ++ sqrt = Math.sqrt, ++ round = Math.round, ++ abs = Math.abs, ++ PI = Math.PI, ++ TWO_PI = PI * 2, ++ HALF_PI = PI / 2, ++ pow = Math.pow, ++ min = Math.min, ++ max = Math.max; ++ ++ /** ++ * Localized variables ++ */ ++ ++ var count = 0; ++ var slice = _.natural.slice; ++ var perf = ((root.performance && root.performance.now) ? root.performance : Date); ++ var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; ++ var getLength = function(obj) { ++ return obj == null ? void 0 : obj['length']; ++ }; ++ var isArrayLike = function(collection) { ++ var length = getLength(collection); ++ return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; ++ }; ++ ++ /** ++ * Cross browser dom events. ++ */ ++ var dom = { ++ ++ temp: (root.document ? root.document.createElement('div') : {}), ++ ++ hasEventListeners: _.isFunction(root.addEventListener), ++ ++ bind: function(elem, event, func, bool) { ++ if (this.hasEventListeners) { ++ elem.addEventListener(event, func, !!bool); ++ } else { ++ elem.attachEvent('on' + event, func); ++ } ++ return dom; ++ }, ++ ++ unbind: function(elem, event, func, bool) { ++ if (dom.hasEventListeners) { ++ elem.removeEventListeners(event, func, !!bool); ++ } else { ++ elem.detachEvent('on' + event, func); ++ } ++ return dom; ++ }, ++ ++ getRequestAnimationFrame: function() { ++ ++ var lastTime = 0; ++ var vendors = ['ms', 'moz', 'webkit', 'o']; ++ var request = root.requestAnimationFrame, cancel; ++ ++ if(!request) { ++ for (var i = 0; i < vendors.length; i++) { ++ request = root[vendors[i] + 'RequestAnimationFrame'] || request; ++ cancel = root[vendors[i] + 'CancelAnimationFrame'] ++ || root[vendors[i] + 'CancelRequestAnimationFrame'] || cancel; ++ } ++ ++ request = request || function(callback, element) { ++ var currTime = new Date().getTime(); ++ var timeToCall = Math.max(0, 16 - (currTime - lastTime)); ++ var id = root.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); ++ lastTime = currTime + timeToCall; ++ return id; ++ }; ++ // cancel = cancel || function(id) { ++ // clearTimeout(id); ++ // }; ++ } ++ ++ request.init = _.once(loop); ++ ++ return request; ++ ++ } ++ ++ }; ++ ++ /** ++ * @class ++ */ ++ var Two = root.Two = function(options) { ++ ++ // Determine what Renderer to use and setup a scene. ++ ++ var params = _.defaults(options || {}, { ++ fullscreen: false, ++ width: 640, ++ height: 480, ++ type: Two.Types.svg, ++ autostart: false ++ }); ++ ++ _.each(params, function(v, k) { ++ if (k === 'fullscreen' || k === 'autostart') { ++ return; ++ } ++ this[k] = v; ++ }, this); ++ ++ // Specified domElement overrides type declaration only if the element does not support declared renderer type. ++ if (_.isElement(params.domElement)) { ++ var tagName = params.domElement.tagName.toLowerCase(); ++ // TODO: Reconsider this if statement's logic. ++ if (!/^(CanvasRenderer-canvas|WebGLRenderer-canvas|SVGRenderer-svg)$/.test(this.type+'-'+tagName)) { ++ this.type = Two.Types[tagName]; ++ } ++ } ++ ++ this.renderer = new Two[this.type](this); ++ Two.Utils.setPlaying.call(this, params.autostart); ++ this.frameCount = 0; ++ ++ if (params.fullscreen) { ++ ++ var fitted = _.bind(fitToWindow, this); ++ _.extend(document.body.style, { ++ overflow: 'hidden', ++ margin: 0, ++ padding: 0, ++ top: 0, ++ left: 0, ++ right: 0, ++ bottom: 0, ++ position: 'fixed' ++ }); ++ _.extend(this.renderer.domElement.style, { ++ display: 'block', ++ top: 0, ++ left: 0, ++ right: 0, ++ bottom: 0, ++ position: 'fixed' ++ }); ++ dom.bind(root, 'resize', fitted); ++ fitted(); ++ ++ ++ } else if (!_.isElement(params.domElement)) { ++ ++ this.renderer.setSize(params.width, params.height, this.ratio); ++ this.width = params.width; ++ this.height = params.height; ++ ++ } ++ ++ this.scene = this.renderer.scene; ++ ++ Two.Instances.push(this); ++ raf.init(); ++ ++ }; ++ ++ _.extend(Two, { ++ ++ /** ++ * Access to root in other files. ++ */ ++ ++ root: root, ++ ++ /** ++ * Primitive ++ */ ++ ++ Array: root.Float32Array || Array, ++ ++ Types: { ++ webgl: 'WebGLRenderer', ++ svg: 'SVGRenderer', ++ canvas: 'CanvasRenderer' ++ }, ++ ++ Version: 'v0.7.0', ++ ++ Identifier: 'two_', ++ ++ Properties: { ++ hierarchy: 'hierarchy', ++ demotion: 'demotion' ++ }, ++ ++ Events: { ++ play: 'play', ++ pause: 'pause', ++ update: 'update', ++ render: 'render', ++ resize: 'resize', ++ change: 'change', ++ remove: 'remove', ++ insert: 'insert', ++ order: 'order', ++ load: 'load' ++ }, ++ ++ Commands: { ++ move: 'M', ++ line: 'L', ++ curve: 'C', ++ close: 'Z' ++ }, ++ ++ Resolution: 8, ++ ++ Instances: [], ++ ++ noConflict: function() { ++ root.Two = previousTwo; ++ return this; ++ }, ++ ++ uniqueId: function() { ++ var id = count; ++ count++; ++ return id; ++ }, ++ ++ Utils: _.extend(_, { ++ ++ performance: perf, ++ ++ defineProperty: function(property) { ++ ++ var object = this; ++ var secret = '_' + property; ++ var flag = '_flag' + property.charAt(0).toUpperCase() + property.slice(1); ++ ++ Object.defineProperty(object, property, { ++ enumerable: true, ++ get: function() { ++ return this[secret]; ++ }, ++ set: function(v) { ++ this[secret] = v; ++ this[flag] = true; ++ } ++ }); ++ ++ }, ++ ++ /** ++ * Release an arbitrary class' events from the two.js corpus and recurse ++ * through its children and or vertices. ++ */ ++ release: function(obj) { ++ ++ if (!_.isObject(obj)) { ++ return; ++ } ++ ++ if (_.isFunction(obj.unbind)) { ++ obj.unbind(); ++ } ++ ++ if (obj.vertices) { ++ if (_.isFunction(obj.vertices.unbind)) { ++ obj.vertices.unbind(); ++ } ++ _.each(obj.vertices, function(v) { ++ if (_.isFunction(v.unbind)) { ++ v.unbind(); ++ } ++ }); ++ } ++ ++ if (obj.children) { ++ _.each(obj.children, function(obj) { ++ Two.Utils.release(obj); ++ }); ++ } ++ ++ }, ++ ++ xhr: function(path, callback) { ++ ++ var xhr = new XMLHttpRequest(); ++ xhr.open('GET', path); ++ ++ xhr.onreadystatechange = function() { ++ if (xhr.readyState === 4 && xhr.status === 200) { ++ callback(xhr.responseText); ++ } ++ }; ++ ++ xhr.send(); ++ return xhr; ++ ++ }, ++ ++ Curve: { ++ ++ CollinearityEpsilon: pow(10, -30), ++ ++ RecursionLimit: 16, ++ ++ CuspLimit: 0, ++ ++ Tolerance: { ++ distance: 0.25, ++ angle: 0, ++ epsilon: 0.01 ++ }, ++ ++ // Lookup tables for abscissas and weights with values for n = 2 .. 16. ++ // As values are symmetric, only store half of them and adapt algorithm ++ // to factor in symmetry. ++ abscissas: [ ++ [ 0.5773502691896257645091488], ++ [0,0.7745966692414833770358531], ++ [ 0.3399810435848562648026658,0.8611363115940525752239465], ++ [0,0.5384693101056830910363144,0.9061798459386639927976269], ++ [ 0.2386191860831969086305017,0.6612093864662645136613996,0.9324695142031520278123016], ++ [0,0.4058451513773971669066064,0.7415311855993944398638648,0.9491079123427585245261897], ++ [ 0.1834346424956498049394761,0.5255324099163289858177390,0.7966664774136267395915539,0.9602898564975362316835609], ++ [0,0.3242534234038089290385380,0.6133714327005903973087020,0.8360311073266357942994298,0.9681602395076260898355762], ++ [ 0.1488743389816312108848260,0.4333953941292471907992659,0.6794095682990244062343274,0.8650633666889845107320967,0.9739065285171717200779640], ++ [0,0.2695431559523449723315320,0.5190961292068118159257257,0.7301520055740493240934163,0.8870625997680952990751578,0.9782286581460569928039380], ++ [ 0.1252334085114689154724414,0.3678314989981801937526915,0.5873179542866174472967024,0.7699026741943046870368938,0.9041172563704748566784659,0.9815606342467192506905491], ++ [0,0.2304583159551347940655281,0.4484927510364468528779129,0.6423493394403402206439846,0.8015780907333099127942065,0.9175983992229779652065478,0.9841830547185881494728294], ++ [ 0.1080549487073436620662447,0.3191123689278897604356718,0.5152486363581540919652907,0.6872929048116854701480198,0.8272013150697649931897947,0.9284348836635735173363911,0.9862838086968123388415973], ++ [0,0.2011940939974345223006283,0.3941513470775633698972074,0.5709721726085388475372267,0.7244177313601700474161861,0.8482065834104272162006483,0.9372733924007059043077589,0.9879925180204854284895657], ++ [ 0.0950125098376374401853193,0.2816035507792589132304605,0.4580167776572273863424194,0.6178762444026437484466718,0.7554044083550030338951012,0.8656312023878317438804679,0.9445750230732325760779884,0.9894009349916499325961542] ++ ], ++ ++ weights: [ ++ [1], ++ [0.8888888888888888888888889,0.5555555555555555555555556], ++ [0.6521451548625461426269361,0.3478548451374538573730639], ++ [0.5688888888888888888888889,0.4786286704993664680412915,0.2369268850561890875142640], ++ [0.4679139345726910473898703,0.3607615730481386075698335,0.1713244923791703450402961], ++ [0.4179591836734693877551020,0.3818300505051189449503698,0.2797053914892766679014678,0.1294849661688696932706114], ++ [0.3626837833783619829651504,0.3137066458778872873379622,0.2223810344533744705443560,0.1012285362903762591525314], ++ [0.3302393550012597631645251,0.3123470770400028400686304,0.2606106964029354623187429,0.1806481606948574040584720,0.0812743883615744119718922], ++ [0.2955242247147528701738930,0.2692667193099963550912269,0.2190863625159820439955349,0.1494513491505805931457763,0.0666713443086881375935688], ++ [0.2729250867779006307144835,0.2628045445102466621806889,0.2331937645919904799185237,0.1862902109277342514260976,0.1255803694649046246346943,0.0556685671161736664827537], ++ [0.2491470458134027850005624,0.2334925365383548087608499,0.2031674267230659217490645,0.1600783285433462263346525,0.1069393259953184309602547,0.0471753363865118271946160], ++ [0.2325515532308739101945895,0.2262831802628972384120902,0.2078160475368885023125232,0.1781459807619457382800467,0.1388735102197872384636018,0.0921214998377284479144218,0.0404840047653158795200216], ++ [0.2152638534631577901958764,0.2051984637212956039659241,0.1855383974779378137417166,0.1572031671581935345696019,0.1215185706879031846894148,0.0801580871597602098056333,0.0351194603317518630318329], ++ [0.2025782419255612728806202,0.1984314853271115764561183,0.1861610000155622110268006,0.1662692058169939335532009,0.1395706779261543144478048,0.1071592204671719350118695,0.0703660474881081247092674,0.0307532419961172683546284], ++ [0.1894506104550684962853967,0.1826034150449235888667637,0.1691565193950025381893121,0.1495959888165767320815017,0.1246289712555338720524763,0.0951585116824927848099251,0.0622535239386478928628438,0.0271524594117540948517806] ++ ] ++ ++ }, ++ ++ /** ++ * Account for high dpi rendering. ++ * http://www.html5rocks.com/en/tutorials/canvas/hidpi/ ++ */ ++ ++ devicePixelRatio: root.devicePixelRatio || 1, ++ ++ getBackingStoreRatio: function(ctx) { ++ return ctx.webkitBackingStorePixelRatio || ++ ctx.mozBackingStorePixelRatio || ++ ctx.msBackingStorePixelRatio || ++ ctx.oBackingStorePixelRatio || ++ ctx.backingStorePixelRatio || 1; ++ }, ++ ++ getRatio: function(ctx) { ++ return Two.Utils.devicePixelRatio / getBackingStoreRatio(ctx); ++ }, ++ ++ /** ++ * Properly defer play calling until after all objects ++ * have been updated with their newest styles. ++ */ ++ setPlaying: function(b) { ++ ++ this.playing = !!b; ++ return this; ++ ++ }, ++ ++ /** ++ * Return the computed matrix of a nested object. ++ * TODO: Optimize traversal. ++ */ ++ getComputedMatrix: function(object, matrix) { ++ ++ matrix = (matrix && matrix.identity()) || new Two.Matrix(); ++ var parent = object, matrices = []; ++ ++ while (parent && parent._matrix) { ++ matrices.push(parent._matrix); ++ parent = parent.parent; ++ } ++ ++ matrices.reverse(); ++ ++ _.each(matrices, function(m) { ++ ++ var e = m.elements; ++ matrix.multiply( ++ e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], e[8], e[9]); ++ ++ }); ++ ++ return matrix; ++ ++ }, ++ ++ deltaTransformPoint: function(matrix, x, y) { ++ ++ var dx = x * matrix.a + y * matrix.c + 0; ++ var dy = x * matrix.b + y * matrix.d + 0; ++ ++ return new Two.Vector(dx, dy); ++ ++ }, ++ ++ /** ++ * https://gist.github.com/2052247 ++ */ ++ decomposeMatrix: function(matrix) { ++ ++ // calculate delta transform point ++ var px = Two.Utils.deltaTransformPoint(matrix, 0, 1); ++ var py = Two.Utils.deltaTransformPoint(matrix, 1, 0); ++ ++ // calculate skew ++ var skewX = ((180 / Math.PI) * Math.atan2(px.y, px.x) - 90); ++ var skewY = ((180 / Math.PI) * Math.atan2(py.y, py.x)); ++ ++ return { ++ translateX: matrix.e, ++ translateY: matrix.f, ++ scaleX: Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b), ++ scaleY: Math.sqrt(matrix.c * matrix.c + matrix.d * matrix.d), ++ skewX: skewX, ++ skewY: skewY, ++ rotation: skewX // rotation is the same as skew x ++ }; ++ ++ }, ++ ++ /** ++ * Walk through item properties and pick the ones of interest. ++ * Will try to resolve styles applied via CSS ++ * ++ * TODO: Reverse calculate `Two.Gradient`s for fill / stroke ++ * of any given path. ++ */ ++ applySvgAttributes: function(node, elem) { ++ ++ var attributes = {}, styles = {}, i, key, value, attr; ++ ++ // Not available in non browser environments ++ if (getComputedStyle) { ++ // Convert CSSStyleDeclaration to a normal object ++ var computedStyles = getComputedStyle(node); ++ i = computedStyles.length; ++ ++ while (i--) { ++ key = computedStyles[i]; ++ value = computedStyles[key]; ++ // Gecko returns undefined for unset properties ++ // Webkit returns the default value ++ if (value !== undefined) { ++ styles[key] = value; ++ } ++ } ++ } ++ ++ // Convert NodeMap to a normal object ++ i = node.attributes.length; ++ while (i--) { ++ attr = node.attributes[i]; ++ attributes[attr.nodeName] = attr.value; ++ } ++ ++ // Getting the correct opacity is a bit tricky, since SVG path elements don't ++ // support opacity as an attribute, but you can apply it via CSS. ++ // So we take the opacity and set (stroke/fill)-opacity to the same value. ++ if (!_.isUndefined(styles.opacity)) { ++ styles['stroke-opacity'] = styles.opacity; ++ styles['fill-opacity'] = styles.opacity; ++ } ++ ++ // Merge attributes and applied styles (attributes take precedence) ++ _.extend(styles, attributes); ++ ++ // Similarly visibility is influenced by the value of both display and visibility. ++ // Calculate a unified value here which defaults to `true`. ++ styles.visible = !(_.isUndefined(styles.display) && styles.display === 'none') ++ || (_.isUndefined(styles.visibility) && styles.visibility === 'hidden'); ++ ++ // Now iterate the whole thing ++ for (key in styles) { ++ value = styles[key]; ++ ++ switch (key) { ++ case 'transform': ++ // TODO: Check this out https://github.com/paperjs/paper.js/blob/master/src/svg/SVGImport.js#L313 ++ if (value === 'none') break; ++ var m = node.getCTM ? node.getCTM() : null; ++ ++ // Might happen when transform string is empty or not valid. ++ if (m === null) break; ++ ++ // // Option 1: edit the underlying matrix and don't force an auto calc. ++ // var m = node.getCTM(); ++ // elem._matrix.manual = true; ++ // elem._matrix.set(m.a, m.b, m.c, m.d, m.e, m.f); ++ ++ // Option 2: Decompose and infer Two.js related properties. ++ var transforms = Two.Utils.decomposeMatrix(node.getCTM()); ++ ++ elem.translation.set(transforms.translateX, transforms.translateY); ++ elem.rotation = transforms.rotation; ++ // Warning: Two.js elements only support uniform scalars... ++ elem.scale = transforms.scaleX; ++ ++ var x = parseFloat((styles.x + '').replace('px')); ++ var y = parseFloat((styles.y + '').replace('px')); ++ ++ // Override based on attributes. ++ if (x) { ++ elem.translation.x = x; ++ } ++ ++ if (y) { ++ elem.translation.y = y; ++ } ++ ++ break; ++ case 'visible': ++ elem.visible = value; ++ break; ++ case 'stroke-linecap': ++ elem.cap = value; ++ break; ++ case 'stroke-linejoin': ++ elem.join = value; ++ break; ++ case 'stroke-miterlimit': ++ elem.miter = value; ++ break; ++ case 'stroke-width': ++ elem.linewidth = parseFloat(value); ++ break; ++ case 'stroke-opacity': ++ case 'fill-opacity': ++ case 'opacity': ++ elem.opacity = parseFloat(value); ++ break; ++ case 'fill': ++ case 'stroke': ++ if (/url\(\#.*\)/i.test(value)) { ++ elem[key] = this.getById( ++ value.replace(/url\(\#(.*)\)/i, '$1')); ++ } else { ++ elem[key] = (value === 'none') ? 'transparent' : value; ++ } ++ break; ++ case 'id': ++ elem.id = value; ++ break; ++ case 'class': ++ elem.classList = value.split(' '); ++ break; ++ } ++ } ++ ++ return elem; ++ ++ }, ++ ++ /** ++ * Read any number of SVG node types and create Two equivalents of them. ++ */ ++ read: { ++ ++ svg: function() { ++ return Two.Utils.read.g.apply(this, arguments); ++ }, ++ ++ g: function(node) { ++ ++ var group = new Two.Group(); ++ ++ // Switched up order to inherit more specific styles ++ Two.Utils.applySvgAttributes.call(this, node, group); ++ ++ for (var i = 0, l = node.childNodes.length; i < l; i++) { ++ var n = node.childNodes[i]; ++ var tag = n.nodeName; ++ if (!tag) return; ++ ++ var tagName = tag.replace(/svg\:/ig, '').toLowerCase(); ++ ++ if (tagName in Two.Utils.read) { ++ var o = Two.Utils.read[tagName].call(group, n); ++ group.add(o); ++ } ++ } ++ ++ return group; ++ ++ }, ++ ++ polygon: function(node, open) { ++ ++ var points = node.getAttribute('points'); ++ ++ var verts = []; ++ points.replace(/(-?[\d\.?]+)[,|\s](-?[\d\.?]+)/g, function(match, p1, p2) { ++ verts.push(new Two.Anchor(parseFloat(p1), parseFloat(p2))); ++ }); ++ ++ var poly = new Two.Path(verts, !open).noStroke(); ++ poly.fill = 'black'; ++ ++ return Two.Utils.applySvgAttributes.call(this, node, poly); ++ ++ }, ++ ++ polyline: function(node) { ++ return Two.Utils.read.polygon.call(this, node, true); ++ }, ++ ++ path: function(node) { ++ ++ var path = node.getAttribute('d'); ++ ++ // Create a Two.Path from the paths. ++ ++ var coord = new Two.Anchor(); ++ var control, coords; ++ var closed = false, relative = false; ++ var commands = path.match(/[a-df-z][^a-df-z]*/ig); ++ var last = commands.length - 1; ++ ++ // Split up polybeziers ++ ++ _.each(commands.slice(0), function(command, i) { ++ ++ var type = command[0]; ++ var lower = type.toLowerCase(); ++ var items = command.slice(1).trim().split(/[\s,]+|(?=\s?[+\-])/); ++ var pre, post, result = [], bin; ++ ++ if (i <= 0) { ++ commands = []; ++ } ++ ++ switch (lower) { ++ case 'h': ++ case 'v': ++ if (items.length > 1) { ++ bin = 1; ++ } ++ break; ++ case 'm': ++ case 'l': ++ case 't': ++ if (items.length > 2) { ++ bin = 2; ++ } ++ break; ++ case 's': ++ case 'q': ++ if (items.length > 4) { ++ bin = 4; ++ } ++ break; ++ case 'c': ++ if (items.length > 6) { ++ bin = 6; ++ } ++ break; ++ case 'a': ++ // TODO: Handle Ellipses ++ break; ++ } ++ ++ if (bin) { ++ ++ for (var j = 0, l = items.length, times = 0; j < l; j+=bin) { ++ ++ var ct = type; ++ if (times > 0) { ++ ++ switch (type) { ++ case 'm': ++ ct = 'l'; ++ break; ++ case 'M': ++ ct = 'L'; ++ break; ++ } ++ ++ } ++ ++ result.push([ct].concat(items.slice(j, j + bin)).join(' ')); ++ times++; ++ ++ } ++ ++ commands = Array.prototype.concat.apply(commands, result); ++ ++ } else { ++ ++ commands.push(command); ++ ++ } ++ ++ }); ++ ++ // Create the vertices for our Two.Path ++ ++ var points = []; ++ _.each(commands, function(command, i) { ++ ++ var result, x, y; ++ var type = command[0]; ++ var lower = type.toLowerCase(); ++ ++ coords = command.slice(1).trim(); ++ coords = coords.replace(/(-?\d+(?:\.\d*)?)[eE]([+\-]?\d+)/g, function(match, n1, n2) { ++ return parseFloat(n1) * pow(10, n2); ++ }); ++ coords = coords.split(/[\s,]+|(?=\s?[+\-])/); ++ relative = type === lower; ++ ++ var x1, y1, x2, y2, x3, y3, x4, y4, reflection; ++ ++ switch (lower) { ++ ++ case 'z': ++ if (i >= last) { ++ closed = true; ++ } else { ++ x = coord.x; ++ y = coord.y; ++ result = new Two.Anchor( ++ x, y, ++ undefined, undefined, ++ undefined, undefined, ++ Two.Commands.close ++ ); ++ } ++ break; ++ ++ case 'm': ++ case 'l': ++ ++ x = parseFloat(coords[0]); ++ y = parseFloat(coords[1]); ++ ++ result = new Two.Anchor( ++ x, y, ++ undefined, undefined, ++ undefined, undefined, ++ lower === 'm' ? Two.Commands.move : Two.Commands.line ++ ); ++ ++ if (relative) { ++ result.addSelf(coord); ++ } ++ ++ // result.controls.left.copy(result); ++ // result.controls.right.copy(result); ++ ++ coord = result; ++ break; ++ ++ case 'h': ++ case 'v': ++ ++ var a = lower === 'h' ? 'x' : 'y'; ++ var b = a === 'x' ? 'y' : 'x'; ++ ++ result = new Two.Anchor( ++ undefined, undefined, ++ undefined, undefined, ++ undefined, undefined, ++ Two.Commands.line ++ ); ++ result[a] = parseFloat(coords[0]); ++ result[b] = coord[b]; ++ ++ if (relative) { ++ result[a] += coord[a]; ++ } ++ ++ // result.controls.left.copy(result); ++ // result.controls.right.copy(result); ++ ++ coord = result; ++ break; ++ ++ case 'c': ++ case 's': ++ ++ x1 = coord.x; ++ y1 = coord.y; ++ ++ if (!control) { ++ control = new Two.Vector();//.copy(coord); ++ } ++ ++ if (lower === 'c') { ++ ++ x2 = parseFloat(coords[0]); ++ y2 = parseFloat(coords[1]); ++ x3 = parseFloat(coords[2]); ++ y3 = parseFloat(coords[3]); ++ x4 = parseFloat(coords[4]); ++ y4 = parseFloat(coords[5]); ++ ++ } else { ++ ++ // Calculate reflection control point for proper x2, y2 ++ // inclusion. ++ ++ reflection = getReflection(coord, control, relative); ++ ++ x2 = reflection.x; ++ y2 = reflection.y; ++ x3 = parseFloat(coords[0]); ++ y3 = parseFloat(coords[1]); ++ x4 = parseFloat(coords[2]); ++ y4 = parseFloat(coords[3]); ++ ++ } ++ ++ if (relative) { ++ x2 += x1; ++ y2 += y1; ++ x3 += x1; ++ y3 += y1; ++ x4 += x1; ++ y4 += y1; ++ } ++ ++ if (!_.isObject(coord.controls)) { ++ Two.Anchor.AppendCurveProperties(coord); ++ } ++ ++ coord.controls.right.set(x2 - coord.x, y2 - coord.y); ++ result = new Two.Anchor( ++ x4, y4, ++ x3 - x4, y3 - y4, ++ undefined, undefined, ++ Two.Commands.curve ++ ); ++ ++ coord = result; ++ control = result.controls.left; ++ ++ break; ++ ++ case 't': ++ case 'q': ++ ++ x1 = coord.x; ++ y1 = coord.y; ++ ++ if (!control) { ++ control = new Two.Vector();//.copy(coord); ++ } ++ ++ if (control.isZero()) { ++ x2 = x1; ++ y2 = y1; ++ } else { ++ x2 = control.x; ++ y1 = control.y; ++ } ++ ++ if (lower === 'q') { ++ ++ x3 = parseFloat(coords[0]); ++ y3 = parseFloat(coords[1]); ++ x4 = parseFloat(coords[1]); ++ y4 = parseFloat(coords[2]); ++ ++ } else { ++ ++ reflection = getReflection(coord, control, relative); ++ ++ x3 = reflection.x; ++ y3 = reflection.y; ++ x4 = parseFloat(coords[0]); ++ y4 = parseFloat(coords[1]); ++ ++ } ++ ++ if (relative) { ++ x2 += x1; ++ y2 += y1; ++ x3 += x1; ++ y3 += y1; ++ x4 += x1; ++ y4 += y1; ++ } ++ ++ if (!_.isObject(coord.controls)) { ++ Two.Anchor.AppendCurveProperties(coord); ++ } ++ ++ coord.controls.right.set(x2 - coord.x, y2 - coord.y); ++ result = new Two.Anchor( ++ x4, y4, ++ x3 - x4, y3 - y4, ++ undefined, undefined, ++ Two.Commands.curve ++ ); ++ ++ coord = result; ++ control = result.controls.left; ++ ++ break; ++ ++ case 'a': ++ ++ // throw new Two.Utils.Error('not yet able to interpret Elliptical Arcs.'); ++ x1 = coord.x; ++ y1 = coord.y; ++ ++ var rx = parseFloat(coords[0]); ++ var ry = parseFloat(coords[1]); ++ var xAxisRotation = parseFloat(coords[2]) * Math.PI / 180; ++ var largeArcFlag = parseFloat(coords[3]); ++ var sweepFlag = parseFloat(coords[4]); ++ ++ x4 = parseFloat(coords[5]); ++ y4 = parseFloat(coords[6]); ++ ++ if (relative) { ++ x4 += x1; ++ y4 += y1; ++ } ++ ++ // http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter ++ ++ // Calculate midpoint mx my ++ var mx = (x4 - x1) / 2; ++ var my = (y4 - y1) / 2; ++ ++ // Calculate x1' y1' F.6.5.1 ++ var _x = mx * Math.cos(xAxisRotation) + my * Math.sin(xAxisRotation); ++ var _y = - mx * Math.sin(xAxisRotation) + my * Math.cos(xAxisRotation); ++ ++ var rx2 = rx * rx; ++ var ry2 = ry * ry; ++ var _x2 = _x * _x; ++ var _y2 = _y * _y; ++ ++ // adjust radii ++ var l = _x2 / rx2 + _y2 / ry2; ++ if (l > 1) { ++ rx *= Math.sqrt(l); ++ ry *= Math.sqrt(l); ++ } ++ ++ var amp = Math.sqrt((rx2 * ry2 - rx2 * _y2 - ry2 * _x2) / (rx2 * _y2 + ry2 * _x2)); ++ ++ if (_.isNaN(amp)) { ++ amp = 0; ++ } else if (largeArcFlag != sweepFlag && amp > 0) { ++ amp *= -1; ++ } ++ ++ // Calculate cx' cy' F.6.5.2 ++ var _cx = amp * rx * _y / ry; ++ var _cy = - amp * ry * _x / rx; ++ ++ // Calculate cx cy F.6.5.3 ++ var cx = _cx * Math.cos(xAxisRotation) - _cy * Math.sin(xAxisRotation) + (x1 + x4) / 2; ++ var cy = _cx * Math.sin(xAxisRotation) + _cy * Math.cos(xAxisRotation) + (y1 + y4) / 2; ++ ++ // vector magnitude ++ var m = function(v) { return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2)); } ++ // ratio between two vectors ++ var r = function(u, v) { return (u[0] * v[0] + u[1] * v[1]) / (m(u) * m(v)) } ++ // angle between two vectors ++ var a = function(u, v) { return (u[0] * v[1] < u[1] * v[0] ? - 1 : 1) * Math.acos(r(u,v)); } ++ ++ // Calculate theta1 and delta theta F.6.5.4 + F.6.5.5 ++ var t1 = a([1, 0], [(_x - _cx) / rx, (_y - _cy) / ry]); ++ var u = [(_x - _cx) / rx, (_y - _cy) / ry]; ++ var v = [( - _x - _cx) / rx, ( - _y - _cy) / ry]; ++ var dt = a(u, v); ++ ++ if (r(u, v) <= -1) dt = Math.PI; ++ if (r(u, v) >= 1) dt = 0; ++ ++ // F.6.5.6 ++ if (largeArcFlag) { ++ dt = mod(dt, Math.PI * 2); ++ } ++ ++ if (sweepFlag && dt > 0) { ++ dt -= Math.PI * 2; ++ } ++ ++ var length = Two.Resolution; ++ ++ // Save a projection of our rotation and translation to apply ++ // to the set of points. ++ var projection = new Two.Matrix() ++ .translate(cx, cy) ++ .rotate(xAxisRotation); ++ ++ // Create a resulting array of Two.Anchor's to export to the ++ // the path. ++ result = _.map(_.range(length), function(i) { ++ var pct = 1 - (i / (length - 1)); ++ var theta = pct * dt + t1; ++ var x = rx * Math.cos(theta); ++ var y = ry * Math.sin(theta); ++ var projected = projection.multiply(x, y, 1); ++ return new Two.Anchor(projected.x, projected.y, false, false, false, false, Two.Commands.line);; ++ }); ++ ++ result.push(new Two.Anchor(x4, y4, false, false, false, false, Two.Commands.line)); ++ ++ coord = result[result.length - 1]; ++ control = coord.controls.left; ++ ++ break; ++ ++ } ++ ++ if (result) { ++ if (_.isArray(result)) { ++ points = points.concat(result); ++ } else { ++ points.push(result); ++ } ++ } ++ ++ }); ++ ++ if (points.length <= 1) { ++ return; ++ } ++ ++ var path = new Two.Path(points, closed, undefined, true).noStroke(); ++ path.fill = 'black'; ++ ++ var rect = path.getBoundingClientRect(true); ++ ++ // Center objects to stay consistent ++ // with the rest of the Two.js API. ++ rect.centroid = { ++ x: rect.left + rect.width / 2, ++ y: rect.top + rect.height / 2 ++ }; ++ ++ _.each(path.vertices, function(v) { ++ v.subSelf(rect.centroid); ++ }); ++ ++ path.translation.addSelf(rect.centroid); ++ ++ return Two.Utils.applySvgAttributes.call(this, node, path); ++ ++ }, ++ ++ circle: function(node) { ++ ++ var x = parseFloat(node.getAttribute('cx')); ++ var y = parseFloat(node.getAttribute('cy')); ++ var r = parseFloat(node.getAttribute('r')); ++ ++ var circle = new Two.Circle(x, y, r).noStroke(); ++ circle.fill = 'black'; ++ ++ return Two.Utils.applySvgAttributes.call(this, node, circle); ++ ++ }, ++ ++ ellipse: function(node) { ++ ++ var x = parseFloat(node.getAttribute('cx')); ++ var y = parseFloat(node.getAttribute('cy')); ++ var width = parseFloat(node.getAttribute('rx')); ++ var height = parseFloat(node.getAttribute('ry')); ++ ++ var ellipse = new Two.Ellipse(x, y, width, height).noStroke(); ++ ellipse.fill = 'black'; ++ ++ return Two.Utils.applySvgAttributes.call(this, node, ellipse); ++ ++ }, ++ ++ rect: function(node) { ++ ++ var x = parseFloat(node.getAttribute('x')) || 0; ++ var y = parseFloat(node.getAttribute('y')) || 0; ++ var width = parseFloat(node.getAttribute('width')); ++ var height = parseFloat(node.getAttribute('height')); ++ ++ var w2 = width / 2; ++ var h2 = height / 2; ++ ++ var rect = new Two.Rectangle(x + w2, y + h2, width, height) ++ .noStroke(); ++ rect.fill = 'black'; ++ ++ return Two.Utils.applySvgAttributes.call(this, node, rect); ++ ++ }, ++ ++ line: function(node) { ++ ++ var x1 = parseFloat(node.getAttribute('x1')); ++ var y1 = parseFloat(node.getAttribute('y1')); ++ var x2 = parseFloat(node.getAttribute('x2')); ++ var y2 = parseFloat(node.getAttribute('y2')); ++ ++ var line = new Two.Line(x1, y1, x2, y2).noFill(); ++ ++ return Two.Utils.applySvgAttributes.call(this, node, line); ++ ++ }, ++ ++ lineargradient: function(node) { ++ ++ var x1 = parseFloat(node.getAttribute('x1')); ++ var y1 = parseFloat(node.getAttribute('y1')); ++ var x2 = parseFloat(node.getAttribute('x2')); ++ var y2 = parseFloat(node.getAttribute('y2')); ++ ++ var ox = (x2 + x1) / 2; ++ var oy = (y2 + y1) / 2; ++ ++ var stops = []; ++ for (var i = 0; i < node.children.length; i++) { ++ ++ var child = node.children[i]; ++ ++ var offset = parseFloat(child.getAttribute('offset')); ++ var color = child.getAttribute('stop-color'); ++ var opacity = child.getAttribute('stop-opacity'); ++ var style = child.getAttribute('style'); ++ ++ if (_.isNull(color)) { ++ var matches = style ? style.match(/stop\-color\:\s?([\#a-fA-F0-9]*)/) : false; ++ color = matches && matches.length > 1 ? matches[1] : undefined; ++ } ++ ++ if (_.isNull(opacity)) { ++ var matches = style ? style.match(/stop\-opacity\:\s?([0-9\.\-]*)/) : false; ++ opacity = matches && matches.length > 1 ? parseFloat(matches[1]) : 1; ++ } ++ ++ stops.push(new Two.Gradient.Stop(offset, color, opacity)); ++ ++ } ++ ++ var gradient = new Two.LinearGradient(x1 - ox, y1 - oy, x2 - ox, ++ y2 - oy, stops); ++ ++ return Two.Utils.applySvgAttributes.call(this, node, gradient); ++ ++ }, ++ ++ radialgradient: function(node) { ++ ++ var cx = parseFloat(node.getAttribute('cx')) || 0; ++ var cy = parseFloat(node.getAttribute('cy')) || 0; ++ var r = parseFloat(node.getAttribute('r')); ++ ++ var fx = parseFloat(node.getAttribute('fx')); ++ var fy = parseFloat(node.getAttribute('fy')); ++ ++ if (_.isNaN(fx)) { ++ fx = cx; ++ } ++ ++ if (_.isNaN(fy)) { ++ fy = cy; ++ } ++ ++ var ox = Math.abs(cx + fx) / 2; ++ var oy = Math.abs(cy + fy) / 2; ++ ++ var stops = []; ++ for (var i = 0; i < node.children.length; i++) { ++ ++ var child = node.children[i]; ++ ++ var offset = parseFloat(child.getAttribute('offset')); ++ var color = child.getAttribute('stop-color'); ++ var opacity = child.getAttribute('stop-opacity'); ++ var style = child.getAttribute('style'); ++ ++ if (_.isNull(color)) { ++ var matches = style ? style.match(/stop\-color\:\s?([\#a-fA-F0-9]*)/) : false; ++ color = matches && matches.length > 1 ? matches[1] : undefined; ++ } ++ ++ if (_.isNull(opacity)) { ++ var matches = style ? style.match(/stop\-opacity\:\s?([0-9\.\-]*)/) : false; ++ opacity = matches && matches.length > 1 ? parseFloat(matches[1]) : 1; ++ } ++ ++ stops.push(new Two.Gradient.Stop(offset, color, opacity)); ++ ++ } ++ ++ var gradient = new Two.RadialGradient(cx - ox, cy - oy, r, ++ stops, fx - ox, fy - oy); ++ ++ return Two.Utils.applySvgAttributes.call(this, node, gradient); ++ ++ } ++ ++ }, ++ ++ /** ++ * Given 2 points (a, b) and corresponding control point for each ++ * return an array of points that represent points plotted along ++ * the curve. Number points determined by limit. ++ */ ++ subdivide: function(x1, y1, x2, y2, x3, y3, x4, y4, limit) { ++ ++ limit = limit || Two.Utils.Curve.RecursionLimit; ++ var amount = limit + 1; ++ ++ // TODO: Issue 73 ++ // Don't recurse if the end points are identical ++ if (x1 === x4 && y1 === y4) { ++ return [new Two.Anchor(x4, y4)]; ++ } ++ ++ return _.map(_.range(0, amount), function(i) { ++ ++ var t = i / amount; ++ var x = getPointOnCubicBezier(t, x1, x2, x3, x4); ++ var y = getPointOnCubicBezier(t, y1, y2, y3, y4); ++ ++ return new Two.Anchor(x, y); ++ ++ }); ++ ++ }, ++ ++ getPointOnCubicBezier: function(t, a, b, c, d) { ++ var k = 1 - t; ++ return (k * k * k * a) + (3 * k * k * t * b) + (3 * k * t * t * c) + ++ (t * t * t * d); ++ }, ++ ++ /** ++ * Given 2 points (a, b) and corresponding control point for each ++ * return a float that represents the length of the curve using ++ * Gauss-Legendre algorithm. Limit iterations of calculation by `limit`. ++ */ ++ getCurveLength: function(x1, y1, x2, y2, x3, y3, x4, y4, limit) { ++ ++ // TODO: Better / fuzzier equality check ++ // Linear calculation ++ if (x1 === x2 && y1 === y2 && x3 === x4 && y3 === y4) { ++ var dx = x4 - x1; ++ var dy = y4 - y1; ++ return sqrt(dx * dx + dy * dy); ++ } ++ ++ // Calculate the coefficients of a Bezier derivative. ++ var ax = 9 * (x2 - x3) + 3 * (x4 - x1), ++ bx = 6 * (x1 + x3) - 12 * x2, ++ cx = 3 * (x2 - x1), ++ ++ ay = 9 * (y2 - y3) + 3 * (y4 - y1), ++ by = 6 * (y1 + y3) - 12 * y2, ++ cy = 3 * (y2 - y1); ++ ++ var integrand = function(t) { ++ // Calculate quadratic equations of derivatives for x and y ++ var dx = (ax * t + bx) * t + cx, ++ dy = (ay * t + by) * t + cy; ++ return sqrt(dx * dx + dy * dy); ++ }; ++ ++ return integrate( ++ integrand, 0, 1, limit || Two.Utils.Curve.RecursionLimit ++ ); ++ ++ }, ++ ++ /** ++ * Integration for `getCurveLength` calculations. Referenced from ++ * Paper.js: https://github.com/paperjs/paper.js/blob/master/src/util/Numerical.js#L101 ++ */ ++ integrate: function(f, a, b, n) { ++ var x = Two.Utils.Curve.abscissas[n - 2], ++ w = Two.Utils.Curve.weights[n - 2], ++ A = 0.5 * (b - a), ++ B = A + a, ++ i = 0, ++ m = (n + 1) >> 1, ++ sum = n & 1 ? w[i++] * f(B) : 0; // Handle odd n ++ while (i < m) { ++ var Ax = A * x[i]; ++ sum += w[i++] * (f(B + Ax) + f(B - Ax)); ++ } ++ return A * sum; ++ }, ++ ++ /** ++ * Creates a set of points that have u, v values for anchor positions ++ */ ++ getCurveFromPoints: function(points, closed) { ++ ++ var l = points.length, last = l - 1; ++ ++ for (var i = 0; i < l; i++) { ++ ++ var point = points[i]; ++ ++ if (!_.isObject(point.controls)) { ++ Two.Anchor.AppendCurveProperties(point); ++ } ++ ++ var prev = closed ? mod(i - 1, l) : max(i - 1, 0); ++ var next = closed ? mod(i + 1, l) : min(i + 1, last); ++ ++ var a = points[prev]; ++ var b = point; ++ var c = points[next]; ++ getControlPoints(a, b, c); ++ ++ b._command = i === 0 ? Two.Commands.move : Two.Commands.curve; ++ ++ b.controls.left.x = _.isNumber(b.controls.left.x) ? b.controls.left.x : b.x; ++ b.controls.left.y = _.isNumber(b.controls.left.y) ? b.controls.left.y : b.y; ++ ++ b.controls.right.x = _.isNumber(b.controls.right.x) ? b.controls.right.x : b.x; ++ b.controls.right.y = _.isNumber(b.controls.right.y) ? b.controls.right.y : b.y; ++ ++ } ++ ++ }, ++ ++ /** ++ * Given three coordinates return the control points for the middle, b, ++ * vertex. ++ */ ++ getControlPoints: function(a, b, c) { ++ ++ var a1 = angleBetween(a, b); ++ var a2 = angleBetween(c, b); ++ ++ var d1 = distanceBetween(a, b); ++ var d2 = distanceBetween(c, b); ++ ++ var mid = (a1 + a2) / 2; ++ ++ // So we know which angle corresponds to which side. ++ ++ b.u = _.isObject(b.controls.left) ? b.controls.left : new Two.Vector(0, 0); ++ b.v = _.isObject(b.controls.right) ? b.controls.right : new Two.Vector(0, 0); ++ ++ // TODO: Issue 73 ++ if (d1 < 0.0001 || d2 < 0.0001) { ++ if (!b._relative) { ++ b.controls.left.copy(b); ++ b.controls.right.copy(b); ++ } ++ return b; ++ } ++ ++ d1 *= 0.33; // Why 0.33? ++ d2 *= 0.33; ++ ++ if (a2 < a1) { ++ mid += HALF_PI; ++ } else { ++ mid -= HALF_PI; ++ } ++ ++ b.controls.left.x = cos(mid) * d1; ++ b.controls.left.y = sin(mid) * d1; ++ ++ mid -= PI; ++ ++ b.controls.right.x = cos(mid) * d2; ++ b.controls.right.y = sin(mid) * d2; ++ ++ if (!b._relative) { ++ b.controls.left.x += b.x; ++ b.controls.left.y += b.y; ++ b.controls.right.x += b.x; ++ b.controls.right.y += b.y; ++ } ++ ++ return b; ++ ++ }, ++ ++ /** ++ * Get the reflection of a point "b" about point "a". Where "a" is in ++ * absolute space and "b" is relative to "a". ++ * ++ * http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes ++ */ ++ getReflection: function(a, b, relative) { ++ ++ return new Two.Vector( ++ 2 * a.x - (b.x + a.x) - (relative ? a.x : 0), ++ 2 * a.y - (b.y + a.y) - (relative ? a.y : 0) ++ ); ++ ++ }, ++ ++ getAnchorsFromArcData: function(center, xAxisRotation, rx, ry, ts, td, ccw) { ++ ++ var matrix = new Two.Matrix() ++ .translate(center.x, center.y) ++ .rotate(xAxisRotation); ++ ++ var l = Two.Resolution; ++ ++ return _.map(_.range(l), function(i) { ++ ++ var pct = (i + 1) / l; ++ if (!!ccw) { ++ pct = 1 - pct; ++ } ++ ++ var theta = pct * td + ts; ++ var x = rx * Math.cos(theta); ++ var y = ry * Math.sin(theta); ++ ++ // x += center.x; ++ // y += center.y; ++ ++ var anchor = new Two.Anchor(x, y); ++ Two.Anchor.AppendCurveProperties(anchor); ++ anchor.command = Two.Commands.line; ++ ++ // TODO: Calculate control points here... ++ ++ return anchor; ++ ++ }); ++ ++ }, ++ ++ ratioBetween: function(A, B) { ++ ++ return (A.x * B.x + A.y * B.y) / (A.length() * B.length()); ++ ++ }, ++ ++ angleBetween: function(A, B) { ++ ++ var dx, dy; ++ ++ if (arguments.length >= 4) { ++ ++ dx = arguments[0] - arguments[2]; ++ dy = arguments[1] - arguments[3]; ++ ++ return atan2(dy, dx); ++ ++ } ++ ++ dx = A.x - B.x; ++ dy = A.y - B.y; ++ ++ return atan2(dy, dx); ++ ++ }, ++ ++ distanceBetweenSquared: function(p1, p2) { ++ ++ var dx = p1.x - p2.x; ++ var dy = p1.y - p2.y; ++ ++ return dx * dx + dy * dy; ++ ++ }, ++ ++ distanceBetween: function(p1, p2) { ++ ++ return sqrt(distanceBetweenSquared(p1, p2)); ++ ++ }, ++ ++ lerp: function(a, b, t) { ++ return t * (b - a) + a; ++ }, ++ ++ // A pretty fast toFixed(3) alternative ++ // See http://jsperf.com/parsefloat-tofixed-vs-math-round/18 ++ toFixed: function(v) { ++ return Math.floor(v * 1000) / 1000; ++ }, ++ ++ mod: function(v, l) { ++ ++ while (v < 0) { ++ v += l; ++ } ++ ++ return v % l; ++ ++ }, ++ ++ /** ++ * Array like collection that triggers inserted and removed events ++ * removed : pop / shift / splice ++ * inserted : push / unshift / splice (with > 2 arguments) ++ */ ++ Collection: function() { ++ ++ Array.call(this); ++ ++ if (arguments.length > 1) { ++ Array.prototype.push.apply(this, arguments); ++ } else if (arguments[0] && Array.isArray(arguments[0])) { ++ Array.prototype.push.apply(this, arguments[0]); ++ } ++ ++ }, ++ ++ // Custom Error Throwing for Two.js ++ ++ Error: function(message) { ++ this.name = 'two.js'; ++ this.message = message; ++ }, ++ ++ Events: { ++ ++ on: function(name, callback) { ++ ++ this._events || (this._events = {}); ++ var list = this._events[name] || (this._events[name] = []); ++ ++ list.push(callback); ++ ++ return this; ++ ++ }, ++ ++ off: function(name, callback) { ++ ++ if (!this._events) { ++ return this; ++ } ++ if (!name && !callback) { ++ this._events = {}; ++ return this; ++ } ++ ++ var names = name ? [name] : _.keys(this._events); ++ for (var i = 0, l = names.length; i < l; i++) { ++ ++ var name = names[i]; ++ var list = this._events[name]; ++ ++ if (!!list) { ++ var events = []; ++ if (callback) { ++ for (var j = 0, k = list.length; j < k; j++) { ++ var ev = list[j]; ++ ev = ev.callback ? ev.callback : ev; ++ if (callback && callback !== ev) { ++ events.push(ev); ++ } ++ } ++ } ++ this._events[name] = events; ++ } ++ } ++ ++ return this; ++ }, ++ ++ trigger: function(name) { ++ if (!this._events) return this; ++ var args = slice.call(arguments, 1); ++ var events = this._events[name]; ++ if (events) trigger(this, events, args); ++ return this; ++ }, ++ ++ listen: function (obj, name, callback) { ++ ++ var bound = this; ++ ++ if (obj) { ++ var ev = function () { ++ callback.apply(bound, arguments); ++ }; ++ ++ // add references about the object that assigned this listener ++ ev.obj = obj; ++ ev.name = name; ++ ev.callback = callback; ++ ++ obj.on(name, ev); ++ } ++ ++ return this; ++ ++ }, ++ ++ ignore: function (obj, name, callback) { ++ ++ obj.off(name, callback); ++ ++ return this; ++ ++ } ++ ++ } ++ ++ }) ++ ++ }); ++ ++ Two.Utils.Events.bind = Two.Utils.Events.on; ++ Two.Utils.Events.unbind = Two.Utils.Events.off; ++ ++ var trigger = function(obj, events, args) { ++ var method; ++ switch (args.length) { ++ case 0: ++ method = function(i) { ++ events[i].call(obj, args[0]); ++ }; ++ break; ++ case 1: ++ method = function(i) { ++ events[i].call(obj, args[0], args[1]); ++ }; ++ break; ++ case 2: ++ method = function(i) { ++ events[i].call(obj, args[0], args[1], args[2]); ++ }; ++ break; ++ case 3: ++ method = function(i) { ++ events[i].call(obj, args[0], args[1], args[2], args[3]); ++ }; ++ break; ++ default: ++ method = function(i) { ++ events[i].apply(obj, args); ++ }; ++ } ++ for (var i = 0; i < events.length; i++) { ++ method(i); ++ } ++ }; ++ ++ Two.Utils.Error.prototype = new Error(); ++ Two.Utils.Error.prototype.constructor = Two.Utils.Error; ++ ++ Two.Utils.Collection.prototype = new Array(); ++ Two.Utils.Collection.prototype.constructor = Two.Utils.Collection; ++ ++ _.extend(Two.Utils.Collection.prototype, Two.Utils.Events, { ++ ++ pop: function() { ++ var popped = Array.prototype.pop.apply(this, arguments); ++ this.trigger(Two.Events.remove, [popped]); ++ return popped; ++ }, ++ ++ shift: function() { ++ var shifted = Array.prototype.shift.apply(this, arguments); ++ this.trigger(Two.Events.remove, [shifted]); ++ return shifted; ++ }, ++ ++ push: function() { ++ var pushed = Array.prototype.push.apply(this, arguments); ++ this.trigger(Two.Events.insert, arguments); ++ return pushed; ++ }, ++ ++ unshift: function() { ++ var unshifted = Array.prototype.unshift.apply(this, arguments); ++ this.trigger(Two.Events.insert, arguments); ++ return unshifted; ++ }, ++ ++ splice: function() { ++ var spliced = Array.prototype.splice.apply(this, arguments); ++ var inserted; ++ ++ this.trigger(Two.Events.remove, spliced); ++ ++ if (arguments.length > 2) { ++ inserted = this.slice(arguments[0], arguments[0] + arguments.length - 2); ++ this.trigger(Two.Events.insert, inserted); ++ this.trigger(Two.Events.order); ++ } ++ return spliced; ++ }, ++ ++ sort: function() { ++ Array.prototype.sort.apply(this, arguments); ++ this.trigger(Two.Events.order); ++ return this; ++ }, ++ ++ reverse: function() { ++ Array.prototype.reverse.apply(this, arguments); ++ this.trigger(Two.Events.order); ++ return this; ++ } ++ ++ }); ++ ++ // Localize utils ++ ++ var distanceBetween = Two.Utils.distanceBetween, ++ getAnchorsFromArcData = Two.Utils.getAnchorsFromArcData, ++ distanceBetweenSquared = Two.Utils.distanceBetweenSquared, ++ ratioBetween = Two.Utils.ratioBetween, ++ angleBetween = Two.Utils.angleBetween, ++ getControlPoints = Two.Utils.getControlPoints, ++ getCurveFromPoints = Two.Utils.getCurveFromPoints, ++ solveSegmentIntersection = Two.Utils.solveSegmentIntersection, ++ decoupleShapes = Two.Utils.decoupleShapes, ++ mod = Two.Utils.mod, ++ getBackingStoreRatio = Two.Utils.getBackingStoreRatio, ++ getPointOnCubicBezier = Two.Utils.getPointOnCubicBezier, ++ getCurveLength = Two.Utils.getCurveLength, ++ integrate = Two.Utils.integrate, ++ getReflection = Two.Utils.getReflection; ++ ++ _.extend(Two.prototype, Two.Utils.Events, { ++ ++ appendTo: function(elem) { ++ ++ elem.appendChild(this.renderer.domElement); ++ return this; ++ ++ }, ++ ++ play: function() { ++ ++ Two.Utils.setPlaying.call(this, true); ++ return this.trigger(Two.Events.play); ++ ++ }, ++ ++ pause: function() { ++ ++ this.playing = false; ++ return this.trigger(Two.Events.pause); ++ ++ }, ++ ++ /** ++ * Update positions and calculations in one pass before rendering. ++ */ ++ update: function() { ++ ++ var animated = !!this._lastFrame; ++ var now = perf.now(); ++ ++ this.frameCount++; ++ ++ if (animated) { ++ this.timeDelta = parseFloat((now - this._lastFrame).toFixed(3)); ++ } ++ this._lastFrame = now; ++ ++ var width = this.width; ++ var height = this.height; ++ var renderer = this.renderer; ++ ++ // Update width / height for the renderer ++ if (width !== renderer.width || height !== renderer.height) { ++ renderer.setSize(width, height, this.ratio); ++ } ++ ++ this.trigger(Two.Events.update, this.frameCount, this.timeDelta); ++ ++ return this.render(); ++ ++ }, ++ ++ /** ++ * Render all drawable - visible objects of the scene. ++ */ ++ render: function() { ++ ++ this.renderer.render(); ++ return this.trigger(Two.Events.render, this.frameCount); ++ ++ }, ++ ++ /** ++ * Convenience Methods ++ */ ++ ++ add: function(o) { ++ ++ var objects = o; ++ if (!(objects instanceof Array)) { ++ objects = _.toArray(arguments); ++ } ++ ++ this.scene.add(objects); ++ return this; ++ ++ }, ++ ++ remove: function(o) { ++ ++ var objects = o; ++ if (!(objects instanceof Array)) { ++ objects = _.toArray(arguments); ++ } ++ ++ this.scene.remove(objects); ++ ++ return this; ++ ++ }, ++ ++ clear: function() { ++ ++ this.scene.remove(_.toArray(this.scene.children)); ++ return this; ++ ++ }, ++ ++ makeLine: function(x1, y1, x2, y2) { ++ ++ var line = new Two.Line(x1, y1, x2, y2); ++ this.scene.add(line); ++ ++ return line; ++ ++ }, ++ ++ makeRectangle: function(x, y, width, height) { ++ ++ var rect = new Two.Rectangle(x, y, width, height); ++ this.scene.add(rect); ++ ++ return rect; ++ ++ }, ++ ++ makeRoundedRectangle: function(x, y, width, height, sides) { ++ ++ var rect = new Two.RoundedRectangle(x, y, width, height, sides); ++ this.scene.add(rect); ++ ++ return rect; ++ ++ }, ++ ++ makeCircle: function(ox, oy, r) { ++ ++ var circle = new Two.Circle(ox, oy, r); ++ this.scene.add(circle); ++ ++ return circle; ++ ++ }, ++ ++ makeEllipse: function(ox, oy, rx, ry) { ++ ++ var ellipse = new Two.Ellipse(ox, oy, rx, ry); ++ this.scene.add(ellipse); ++ ++ return ellipse; ++ ++ }, ++ ++ makeStar: function(ox, oy, or, ir, sides) { ++ ++ var star = new Two.Star(ox, oy, or, ir, sides); ++ this.scene.add(star); ++ ++ return star; ++ ++ }, ++ ++ makeCurve: function(p) { ++ ++ var l = arguments.length, points = p; ++ if (!_.isArray(p)) { ++ points = []; ++ for (var i = 0; i < l; i+=2) { ++ var x = arguments[i]; ++ if (!_.isNumber(x)) { ++ break; ++ } ++ var y = arguments[i + 1]; ++ points.push(new Two.Anchor(x, y)); ++ } ++ } ++ ++ var last = arguments[l - 1]; ++ var curve = new Two.Path(points, !(_.isBoolean(last) ? last : undefined), true); ++ var rect = curve.getBoundingClientRect(); ++ curve.center().translation ++ .set(rect.left + rect.width / 2, rect.top + rect.height / 2); ++ ++ this.scene.add(curve); ++ ++ return curve; ++ ++ }, ++ ++ makePolygon: function(ox, oy, r, sides) { ++ ++ var poly = new Two.Polygon(ox, oy, r, sides); ++ this.scene.add(poly); ++ ++ return poly; ++ ++ }, ++ ++ /* ++ * Make an Arc Segment ++ */ ++ ++ makeArcSegment: function(ox, oy, ir, or, sa, ea, res) { ++ var arcSegment = new Two.ArcSegment(ox, oy, ir, or, sa, ea, res); ++ this.scene.add(arcSegment); ++ return arcSegment; ++ }, ++ ++ /** ++ * Convenience method to make and draw a Two.Path. ++ */ ++ makePath: function(p) { ++ ++ var l = arguments.length, points = p; ++ if (!_.isArray(p)) { ++ points = []; ++ for (var i = 0; i < l; i+=2) { ++ var x = arguments[i]; ++ if (!_.isNumber(x)) { ++ break; ++ } ++ var y = arguments[i + 1]; ++ points.push(new Two.Anchor(x, y)); ++ } ++ } ++ ++ var last = arguments[l - 1]; ++ var path = new Two.Path(points, !(_.isBoolean(last) ? last : undefined)); ++ var rect = path.getBoundingClientRect(); ++ path.center().translation ++ .set(rect.left + rect.width / 2, rect.top + rect.height / 2); ++ ++ this.scene.add(path); ++ ++ return path; ++ ++ }, ++ ++ /** ++ * Convenience method to make and add a Two.Text. ++ */ ++ makeText: function(message, x, y, styles) { ++ var text = new Two.Text(message, x, y, styles); ++ this.add(text); ++ return text; ++ }, ++ ++ /** ++ * Convenience method to make and add a Two.LinearGradient. ++ */ ++ makeLinearGradient: function(x1, y1, x2, y2 /* stops */) { ++ ++ var stops = slice.call(arguments, 4); ++ var gradient = new Two.LinearGradient(x1, y1, x2, y2, stops); ++ ++ this.add(gradient); ++ ++ return gradient; ++ ++ }, ++ ++ /** ++ * Convenience method to make and add a Two.RadialGradient. ++ */ ++ makeRadialGradient: function(x1, y1, r /* stops */) { ++ ++ var stops = slice.call(arguments, 3); ++ var gradient = new Two.RadialGradient(x1, y1, r, stops); ++ ++ this.add(gradient); ++ ++ return gradient; ++ ++ }, ++ ++ makeSprite: function(path, x, y, cols, rows, frameRate, autostart) { ++ ++ var sprite = new Two.Sprite(path, x, y, cols, rows, frameRate); ++ if (!!autostart) { ++ sprite.play(); ++ } ++ this.add(sprite); ++ ++ return sprite; ++ ++ }, ++ ++ makeImageSequence: function(paths, x, y, frameRate, autostart) { ++ ++ var imageSequence = new Two.ImageSequence(paths, x, y, frameRate); ++ if (!!autostart) { ++ imageSequence.play(); ++ } ++ this.add(imageSequence); ++ ++ return imageSequence; ++ ++ }, ++ ++ makeTexture: function(path, callback) { ++ ++ var texture = new Two.Texture(path, callback); ++ return texture; ++ ++ }, ++ ++ makeGroup: function(o) { ++ ++ var objects = o; ++ if (!(objects instanceof Array)) { ++ objects = _.toArray(arguments); ++ } ++ ++ var group = new Two.Group(); ++ this.scene.add(group); ++ group.add(objects); ++ ++ return group; ++ ++ }, ++ ++ /** ++ * Interpret an SVG Node and add it to this instance's scene. The ++ * distinction should be made that this doesn't `import` svg's, it solely ++ * interprets them into something compatible for Two.js — this is slightly ++ * different than a direct transcription. ++ * ++ * @param {Object} svgNode - The node to be parsed ++ * @param {Boolean} shallow - Don't create a top-most group but ++ * append all contents directly ++ */ ++ interpret: function(svgNode, shallow) { ++ ++ var tag = svgNode.tagName.toLowerCase(); ++ ++ if (!(tag in Two.Utils.read)) { ++ return null; ++ } ++ ++ var node = Two.Utils.read[tag].call(this, svgNode); ++ ++ if (shallow && node instanceof Two.Group) { ++ this.add(node.children); ++ } else { ++ this.add(node); ++ } ++ ++ return node; ++ ++ }, ++ ++ /** ++ * Load an SVG file / text and interpret. ++ */ ++ load: function(text, callback) { ++ ++ var nodes = [], elem, i; ++ ++ if (/.*\.svg/ig.test(text)) { ++ ++ Two.Utils.xhr(text, _.bind(function(data) { ++ ++ dom.temp.innerHTML = data; ++ for (i = 0; i < dom.temp.children.length; i++) { ++ elem = dom.temp.children[i]; ++ nodes.push(this.interpret(elem)); ++ } ++ ++ callback(nodes.length <= 1 ? nodes[0] : nodes, ++ dom.temp.children.length <= 1 ? dom.temp.children[0] : dom.temp.children); ++ ++ }, this)); ++ ++ return this; ++ ++ } ++ ++ dom.temp.innerHTML = text; ++ for (i = 0; i < dom.temp.children.length; i++) { ++ elem = dom.temp.children[i]; ++ nodes.push(this.interpret(elem)); ++ } ++ ++ callback(nodes.length <= 1 ? nodes[0] : nodes, ++ dom.temp.children.length <= 1 ? dom.temp.children[0] : dom.temp.children); ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ function fitToWindow() { ++ ++ var wr = document.body.getBoundingClientRect(); ++ ++ var width = this.width = wr.width; ++ var height = this.height = wr.height; ++ ++ this.renderer.setSize(width, height, this.ratio); ++ this.trigger(Two.Events.resize, width, height); ++ ++ } ++ ++ // Request Animation Frame ++ ++ var raf = dom.getRequestAnimationFrame(); ++ ++ function loop() { ++ ++ raf(loop); ++ ++ for (var i = 0; i < Two.Instances.length; i++) { ++ var t = Two.Instances[i]; ++ if (t.playing) { ++ t.update(); ++ } ++ } ++ ++ } ++ ++ if (typeof define === 'function' && define.amd) { ++ define('two', [], function() { ++ return Two; ++ }); ++ } else if (typeof module != 'undefined' && module.exports) { ++ module.exports = Two; ++ } ++ ++ return Two; ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var _ = Two.Utils; ++ ++ var Registry = Two.Registry = function() { ++ ++ this.map = {}; ++ ++ }; ++ ++ _.extend(Registry, { ++ ++ }); ++ ++ _.extend(Registry.prototype, { ++ ++ add: function(id, obj) { ++ this.map[id] = obj; ++ return this; ++ }, ++ ++ remove: function(id) { ++ delete this.map[id]; ++ return this; ++ }, ++ ++ get: function(id) { ++ return this.map[id]; ++ }, ++ ++ contains: function(id) { ++ return id in this.map; ++ } ++ ++ }); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var _ = Two.Utils; ++ ++ var Vector = Two.Vector = function(x, y) { ++ ++ this.x = x || 0; ++ this.y = y || 0; ++ ++ }; ++ ++ _.extend(Vector, { ++ ++ zero: new Two.Vector() ++ ++ }); ++ ++ _.extend(Vector.prototype, Two.Utils.Events, { ++ ++ set: function(x, y) { ++ this.x = x; ++ this.y = y; ++ return this; ++ }, ++ ++ copy: function(v) { ++ this.x = v.x; ++ this.y = v.y; ++ return this; ++ }, ++ ++ clear: function() { ++ this.x = 0; ++ this.y = 0; ++ return this; ++ }, ++ ++ clone: function() { ++ return new Vector(this.x, this.y); ++ }, ++ ++ add: function(v1, v2) { ++ this.x = v1.x + v2.x; ++ this.y = v1.y + v2.y; ++ return this; ++ }, ++ ++ addSelf: function(v) { ++ this.x += v.x; ++ this.y += v.y; ++ return this; ++ }, ++ ++ sub: function(v1, v2) { ++ this.x = v1.x - v2.x; ++ this.y = v1.y - v2.y; ++ return this; ++ }, ++ ++ subSelf: function(v) { ++ this.x -= v.x; ++ this.y -= v.y; ++ return this; ++ }, ++ ++ multiplySelf: function(v) { ++ this.x *= v.x; ++ this.y *= v.y; ++ return this; ++ }, ++ ++ multiplyScalar: function(s) { ++ this.x *= s; ++ this.y *= s; ++ return this; ++ }, ++ ++ divideScalar: function(s) { ++ if (s) { ++ this.x /= s; ++ this.y /= s; ++ } else { ++ this.set(0, 0); ++ } ++ return this; ++ }, ++ ++ negate: function() { ++ return this.multiplyScalar(-1); ++ }, ++ ++ dot: function(v) { ++ return this.x * v.x + this.y * v.y; ++ }, ++ ++ lengthSquared: function() { ++ return this.x * this.x + this.y * this.y; ++ }, ++ ++ length: function() { ++ return Math.sqrt(this.lengthSquared()); ++ }, ++ ++ normalize: function() { ++ return this.divideScalar(this.length()); ++ }, ++ ++ distanceTo: function(v) { ++ return Math.sqrt(this.distanceToSquared(v)); ++ }, ++ ++ distanceToSquared: function(v) { ++ var dx = this.x - v.x, ++ dy = this.y - v.y; ++ return dx * dx + dy * dy; ++ }, ++ ++ setLength: function(l) { ++ return this.normalize().multiplyScalar(l); ++ }, ++ ++ equals: function(v, eps) { ++ eps = (typeof eps === 'undefined') ? 0.0001 : eps; ++ return (this.distanceTo(v) < eps); ++ }, ++ ++ lerp: function(v, t) { ++ var x = (v.x - this.x) * t + this.x; ++ var y = (v.y - this.y) * t + this.y; ++ return this.set(x, y); ++ }, ++ ++ isZero: function(eps) { ++ eps = (typeof eps === 'undefined') ? 0.0001 : eps; ++ return (this.length() < eps); ++ }, ++ ++ toString: function() { ++ return this.x + ', ' + this.y; ++ }, ++ ++ toObject: function() { ++ return { x: this.x, y: this.y }; ++ }, ++ ++ rotate: function (radians) { ++ var cos = Math.cos(radians); ++ var sin = Math.sin(radians); ++ this.x = this.x * cos - this.y * sin; ++ this.y = this.x * sin + this.y * cos; ++ return this; ++ } ++ ++ }); ++ ++ var BoundProto = { ++ ++ set: function(x, y) { ++ this._x = x; ++ this._y = y; ++ return this.trigger(Two.Events.change); ++ }, ++ ++ copy: function(v) { ++ this._x = v.x; ++ this._y = v.y; ++ return this.trigger(Two.Events.change); ++ }, ++ ++ clear: function() { ++ this._x = 0; ++ this._y = 0; ++ return this.trigger(Two.Events.change); ++ }, ++ ++ clone: function() { ++ return new Vector(this._x, this._y); ++ }, ++ ++ add: function(v1, v2) { ++ this._x = v1.x + v2.x; ++ this._y = v1.y + v2.y; ++ return this.trigger(Two.Events.change); ++ }, ++ ++ addSelf: function(v) { ++ this._x += v.x; ++ this._y += v.y; ++ return this.trigger(Two.Events.change); ++ }, ++ ++ sub: function(v1, v2) { ++ this._x = v1.x - v2.x; ++ this._y = v1.y - v2.y; ++ return this.trigger(Two.Events.change); ++ }, ++ ++ subSelf: function(v) { ++ this._x -= v.x; ++ this._y -= v.y; ++ return this.trigger(Two.Events.change); ++ }, ++ ++ multiplySelf: function(v) { ++ this._x *= v.x; ++ this._y *= v.y; ++ return this.trigger(Two.Events.change); ++ }, ++ ++ multiplyScalar: function(s) { ++ this._x *= s; ++ this._y *= s; ++ return this.trigger(Two.Events.change); ++ }, ++ ++ divideScalar: function(s) { ++ if (s) { ++ this._x /= s; ++ this._y /= s; ++ return this.trigger(Two.Events.change); ++ } ++ return this.clear(); ++ }, ++ ++ negate: function() { ++ return this.multiplyScalar(-1); ++ }, ++ ++ dot: function(v) { ++ return this._x * v.x + this._y * v.y; ++ }, ++ ++ lengthSquared: function() { ++ return this._x * this._x + this._y * this._y; ++ }, ++ ++ length: function() { ++ return Math.sqrt(this.lengthSquared()); ++ }, ++ ++ normalize: function() { ++ return this.divideScalar(this.length()); ++ }, ++ ++ distanceTo: function(v) { ++ return Math.sqrt(this.distanceToSquared(v)); ++ }, ++ ++ distanceToSquared: function(v) { ++ var dx = this._x - v.x, ++ dy = this._y - v.y; ++ return dx * dx + dy * dy; ++ }, ++ ++ setLength: function(l) { ++ return this.normalize().multiplyScalar(l); ++ }, ++ ++ equals: function(v, eps) { ++ eps = (typeof eps === 'undefined') ? 0.0001 : eps; ++ return (this.distanceTo(v) < eps); ++ }, ++ ++ lerp: function(v, t) { ++ var x = (v.x - this._x) * t + this._x; ++ var y = (v.y - this._y) * t + this._y; ++ return this.set(x, y); ++ }, ++ ++ isZero: function(eps) { ++ eps = (typeof eps === 'undefined') ? 0.0001 : eps; ++ return (this.length() < eps); ++ }, ++ ++ toString: function() { ++ return this._x + ', ' + this._y; ++ }, ++ ++ toObject: function() { ++ return { x: this._x, y: this._y }; ++ }, ++ ++ rotate: function (radians) { ++ var cos = Math.cos(radians); ++ var sin = Math.sin(radians); ++ this._x = this._x * cos - this._y * sin; ++ this._y = this._x * sin + this._y * cos; ++ return this; ++ } ++ ++ }; ++ ++ var xgs = { ++ enumerable: true, ++ get: function() { ++ return this._x; ++ }, ++ set: function(v) { ++ this._x = v; ++ this.trigger(Two.Events.change, 'x'); ++ } ++ }; ++ ++ var ygs = { ++ enumerable: true, ++ get: function() { ++ return this._y; ++ }, ++ set: function(v) { ++ this._y = v; ++ this.trigger(Two.Events.change, 'y'); ++ } ++ }; ++ ++ /** ++ * Override Backbone bind / on in order to add properly broadcasting. ++ * This allows Two.Vector to not broadcast events unless event listeners ++ * are explicity bound to it. ++ */ ++ ++ Two.Vector.prototype.bind = Two.Vector.prototype.on = function() { ++ ++ if (!this._bound) { ++ this._x = this.x; ++ this._y = this.y; ++ Object.defineProperty(this, 'x', xgs); ++ Object.defineProperty(this, 'y', ygs); ++ _.extend(this, BoundProto); ++ this._bound = true; // Reserved for event initialization check ++ } ++ ++ Two.Utils.Events.bind.apply(this, arguments); ++ ++ return this; ++ ++ }; ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ // Localized variables ++ var commands = Two.Commands; ++ var _ = Two.Utils; ++ ++ /** ++ * An object that holds 3 `Two.Vector`s, the anchor point and its ++ * corresponding handles: `left` and `right`. ++ */ ++ var Anchor = Two.Anchor = function(x, y, ux, uy, vx, vy, command) { ++ ++ Two.Vector.call(this, x, y); ++ ++ this._broadcast = _.bind(function() { ++ this.trigger(Two.Events.change); ++ }, this); ++ ++ this._command = command || commands.move; ++ this._relative = true; ++ ++ if (!command) { ++ return this; ++ } ++ ++ Anchor.AppendCurveProperties(this); ++ ++ if (_.isNumber(ux)) { ++ this.controls.left.x = ux; ++ } ++ if (_.isNumber(uy)) { ++ this.controls.left.y = uy; ++ } ++ if (_.isNumber(vx)) { ++ this.controls.right.x = vx; ++ } ++ if (_.isNumber(vy)) { ++ this.controls.right.y = vy; ++ } ++ ++ }; ++ ++ _.extend(Anchor, { ++ ++ AppendCurveProperties: function(anchor) { ++ anchor.controls = { ++ left: new Two.Vector(0, 0), ++ right: new Two.Vector(0, 0) ++ }; ++ } ++ ++ }); ++ ++ var AnchorProto = { ++ ++ listen: function() { ++ ++ if (!_.isObject(this.controls)) { ++ Anchor.AppendCurveProperties(this); ++ } ++ ++ this.controls.left.bind(Two.Events.change, this._broadcast); ++ this.controls.right.bind(Two.Events.change, this._broadcast); ++ ++ return this; ++ ++ }, ++ ++ ignore: function() { ++ ++ this.controls.left.unbind(Two.Events.change, this._broadcast); ++ this.controls.right.unbind(Two.Events.change, this._broadcast); ++ ++ return this; ++ ++ }, ++ ++ clone: function() { ++ ++ var controls = this.controls; ++ ++ var clone = new Two.Anchor( ++ this.x, ++ this.y, ++ controls && controls.left.x, ++ controls && controls.left.y, ++ controls && controls.right.x, ++ controls && controls.right.y, ++ this.command ++ ); ++ clone.relative = this._relative; ++ return clone; ++ ++ }, ++ ++ toObject: function() { ++ var o = { ++ x: this.x, ++ y: this.y ++ }; ++ if (this._command) { ++ o.command = this._command; ++ } ++ if (this._relative) { ++ o.relative = this._relative; ++ } ++ if (this.controls) { ++ o.controls = { ++ left: this.controls.left.toObject(), ++ right: this.controls.right.toObject() ++ }; ++ } ++ return o; ++ }, ++ ++ toString: function() { ++ if (!this.controls) { ++ return [this._x, this._y].join(', '); ++ } ++ return [this._x, this._y, this.controls.left.x, this.controls.left.y, ++ this.controls.right.x, this.controls.right.y].join(', '); ++ } ++ ++ }; ++ ++ Object.defineProperty(Anchor.prototype, 'command', { ++ ++ enumerable: true, ++ ++ get: function() { ++ return this._command; ++ }, ++ ++ set: function(c) { ++ this._command = c; ++ if (this._command === commands.curve && !_.isObject(this.controls)) { ++ Anchor.AppendCurveProperties(this); ++ } ++ return this.trigger(Two.Events.change); ++ } ++ ++ }); ++ ++ Object.defineProperty(Anchor.prototype, 'relative', { ++ ++ enumerable: true, ++ ++ get: function() { ++ return this._relative; ++ }, ++ ++ set: function(b) { ++ if (this._relative == b) { ++ return this; ++ } ++ this._relative = !!b; ++ return this.trigger(Two.Events.change); ++ } ++ ++ }); ++ ++ _.extend(Anchor.prototype, Two.Vector.prototype, AnchorProto); ++ ++ // Make it possible to bind and still have the Anchor specific ++ // inheritance from Two.Vector ++ Two.Anchor.prototype.bind = Two.Anchor.prototype.on = function() { ++ Two.Vector.prototype.bind.apply(this, arguments); ++ _.extend(this, AnchorProto); ++ }; ++ ++ Two.Anchor.prototype.unbind = Two.Anchor.prototype.off = function() { ++ Two.Vector.prototype.unbind.apply(this, arguments); ++ _.extend(this, AnchorProto); ++ }; ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ /** ++ * Constants ++ */ ++ var cos = Math.cos, sin = Math.sin, tan = Math.tan; ++ var _ = Two.Utils; ++ ++ /** ++ * Two.Matrix contains an array of elements that represent ++ * the two dimensional 3 x 3 matrix as illustrated below: ++ * ++ * ===== ++ * a b c ++ * d e f ++ * g h i // this row is not really used in 2d transformations ++ * ===== ++ * ++ * String order is for transform strings: a, d, b, e, c, f ++ * ++ * @class ++ */ ++ var Matrix = Two.Matrix = function(a, b, c, d, e, f) { ++ ++ this.elements = new Two.Array(9); ++ ++ var elements = a; ++ if (!_.isArray(elements)) { ++ elements = _.toArray(arguments); ++ } ++ ++ // initialize the elements with default values. ++ ++ this.identity().set(elements); ++ ++ }; ++ ++ _.extend(Matrix, { ++ ++ Identity: [ ++ 1, 0, 0, ++ 0, 1, 0, ++ 0, 0, 1 ++ ], ++ ++ /** ++ * Multiply two matrix 3x3 arrays ++ */ ++ Multiply: function(A, B, C) { ++ ++ if (B.length <= 3) { // Multiply Vector ++ ++ var x, y, z, e = A; ++ ++ var a = B[0] || 0, ++ b = B[1] || 0, ++ c = B[2] || 0; ++ ++ // Go down rows first ++ // a, d, g, b, e, h, c, f, i ++ ++ x = e[0] * a + e[1] * b + e[2] * c; ++ y = e[3] * a + e[4] * b + e[5] * c; ++ z = e[6] * a + e[7] * b + e[8] * c; ++ ++ return { x: x, y: y, z: z }; ++ ++ } ++ ++ var A0 = A[0], A1 = A[1], A2 = A[2]; ++ var A3 = A[3], A4 = A[4], A5 = A[5]; ++ var A6 = A[6], A7 = A[7], A8 = A[8]; ++ ++ var B0 = B[0], B1 = B[1], B2 = B[2]; ++ var B3 = B[3], B4 = B[4], B5 = B[5]; ++ var B6 = B[6], B7 = B[7], B8 = B[8]; ++ ++ C = C || new Two.Array(9); ++ ++ C[0] = A0 * B0 + A1 * B3 + A2 * B6; ++ C[1] = A0 * B1 + A1 * B4 + A2 * B7; ++ C[2] = A0 * B2 + A1 * B5 + A2 * B8; ++ C[3] = A3 * B0 + A4 * B3 + A5 * B6; ++ C[4] = A3 * B1 + A4 * B4 + A5 * B7; ++ C[5] = A3 * B2 + A4 * B5 + A5 * B8; ++ C[6] = A6 * B0 + A7 * B3 + A8 * B6; ++ C[7] = A6 * B1 + A7 * B4 + A8 * B7; ++ C[8] = A6 * B2 + A7 * B5 + A8 * B8; ++ ++ return C; ++ ++ } ++ ++ }); ++ ++ _.extend(Matrix.prototype, Two.Utils.Events, { ++ ++ /** ++ * Takes an array of elements or the arguments list itself to ++ * set and update the current matrix's elements. Only updates ++ * specified values. ++ */ ++ set: function(a) { ++ ++ var elements = a; ++ if (!_.isArray(elements)) { ++ elements = _.toArray(arguments); ++ } ++ ++ _.extend(this.elements, elements); ++ ++ return this.trigger(Two.Events.change); ++ ++ }, ++ ++ /** ++ * Turn matrix to identity, like resetting. ++ */ ++ identity: function() { ++ ++ this.set(Matrix.Identity); ++ ++ return this; ++ ++ }, ++ ++ /** ++ * Multiply scalar or multiply by another matrix. ++ */ ++ multiply: function(a, b, c, d, e, f, g, h, i) { ++ ++ var elements = arguments, l = elements.length; ++ ++ // Multiply scalar ++ ++ if (l <= 1) { ++ ++ _.each(this.elements, function(v, i) { ++ this.elements[i] = v * a; ++ }, this); ++ ++ return this.trigger(Two.Events.change); ++ ++ } ++ ++ if (l <= 3) { // Multiply Vector ++ ++ var x, y, z; ++ a = a || 0; ++ b = b || 0; ++ c = c || 0; ++ e = this.elements; ++ ++ // Go down rows first ++ // a, d, g, b, e, h, c, f, i ++ ++ x = e[0] * a + e[1] * b + e[2] * c; ++ y = e[3] * a + e[4] * b + e[5] * c; ++ z = e[6] * a + e[7] * b + e[8] * c; ++ ++ return { x: x, y: y, z: z }; ++ ++ } ++ ++ // Multiple matrix ++ ++ var A = this.elements; ++ var B = elements; ++ ++ var A0 = A[0], A1 = A[1], A2 = A[2]; ++ var A3 = A[3], A4 = A[4], A5 = A[5]; ++ var A6 = A[6], A7 = A[7], A8 = A[8]; ++ ++ var B0 = B[0], B1 = B[1], B2 = B[2]; ++ var B3 = B[3], B4 = B[4], B5 = B[5]; ++ var B6 = B[6], B7 = B[7], B8 = B[8]; ++ ++ this.elements[0] = A0 * B0 + A1 * B3 + A2 * B6; ++ this.elements[1] = A0 * B1 + A1 * B4 + A2 * B7; ++ this.elements[2] = A0 * B2 + A1 * B5 + A2 * B8; ++ ++ this.elements[3] = A3 * B0 + A4 * B3 + A5 * B6; ++ this.elements[4] = A3 * B1 + A4 * B4 + A5 * B7; ++ this.elements[5] = A3 * B2 + A4 * B5 + A5 * B8; ++ ++ this.elements[6] = A6 * B0 + A7 * B3 + A8 * B6; ++ this.elements[7] = A6 * B1 + A7 * B4 + A8 * B7; ++ this.elements[8] = A6 * B2 + A7 * B5 + A8 * B8; ++ ++ return this.trigger(Two.Events.change); ++ ++ }, ++ ++ inverse: function(out) { ++ ++ var a = this.elements; ++ out = out || new Two.Matrix(); ++ ++ var a00 = a[0], a01 = a[1], a02 = a[2]; ++ var a10 = a[3], a11 = a[4], a12 = a[5]; ++ var a20 = a[6], a21 = a[7], a22 = a[8]; ++ ++ var b01 = a22 * a11 - a12 * a21; ++ var b11 = -a22 * a10 + a12 * a20; ++ var b21 = a21 * a10 - a11 * a20; ++ ++ // Calculate the determinant ++ var det = a00 * b01 + a01 * b11 + a02 * b21; ++ ++ if (!det) { ++ return null; ++ } ++ ++ det = 1.0 / det; ++ ++ out.elements[0] = b01 * det; ++ out.elements[1] = (-a22 * a01 + a02 * a21) * det; ++ out.elements[2] = (a12 * a01 - a02 * a11) * det; ++ out.elements[3] = b11 * det; ++ out.elements[4] = (a22 * a00 - a02 * a20) * det; ++ out.elements[5] = (-a12 * a00 + a02 * a10) * det; ++ out.elements[6] = b21 * det; ++ out.elements[7] = (-a21 * a00 + a01 * a20) * det; ++ out.elements[8] = (a11 * a00 - a01 * a10) * det; ++ ++ return out; ++ ++ }, ++ ++ /** ++ * Set a scalar onto the matrix. ++ */ ++ scale: function(sx, sy) { ++ ++ var l = arguments.length; ++ if (l <= 1) { ++ sy = sx; ++ } ++ ++ return this.multiply(sx, 0, 0, 0, sy, 0, 0, 0, 1); ++ ++ }, ++ ++ /** ++ * Rotate the matrix. ++ */ ++ rotate: function(radians) { ++ ++ var c = cos(radians); ++ var s = sin(radians); ++ ++ return this.multiply(c, -s, 0, s, c, 0, 0, 0, 1); ++ ++ }, ++ ++ /** ++ * Translate the matrix. ++ */ ++ translate: function(x, y) { ++ ++ return this.multiply(1, 0, x, 0, 1, y, 0, 0, 1); ++ ++ }, ++ ++ /* ++ * Skew the matrix by an angle in the x axis direction. ++ */ ++ skewX: function(radians) { ++ ++ var a = tan(radians); ++ ++ return this.multiply(1, a, 0, 0, 1, 0, 0, 0, 1); ++ ++ }, ++ ++ /* ++ * Skew the matrix by an angle in the y axis direction. ++ */ ++ skewY: function(radians) { ++ ++ var a = tan(radians); ++ ++ return this.multiply(1, 0, 0, a, 1, 0, 0, 0, 1); ++ ++ }, ++ ++ /** ++ * Create a transform string to be used with rendering apis. ++ */ ++ toString: function(fullMatrix) { ++ var temp = []; ++ ++ this.toArray(fullMatrix, temp); ++ ++ return temp.join(' '); ++ ++ }, ++ ++ /** ++ * Create a transform array to be used with rendering apis. ++ */ ++ toArray: function(fullMatrix, output) { ++ ++ var elements = this.elements; ++ var hasOutput = !!output; ++ ++ var a = parseFloat(elements[0].toFixed(3)); ++ var b = parseFloat(elements[1].toFixed(3)); ++ var c = parseFloat(elements[2].toFixed(3)); ++ var d = parseFloat(elements[3].toFixed(3)); ++ var e = parseFloat(elements[4].toFixed(3)); ++ var f = parseFloat(elements[5].toFixed(3)); ++ ++ if (!!fullMatrix) { ++ ++ var g = parseFloat(elements[6].toFixed(3)); ++ var h = parseFloat(elements[7].toFixed(3)); ++ var i = parseFloat(elements[8].toFixed(3)); ++ ++ if (hasOutput) { ++ output[0] = a; ++ output[1] = d; ++ output[2] = g; ++ output[3] = b; ++ output[4] = e; ++ output[5] = h; ++ output[6] = c; ++ output[7] = f; ++ output[8] = i; ++ return; ++ } ++ ++ return [ ++ a, d, g, b, e, h, c, f, i ++ ]; ++ } ++ ++ if (hasOutput) { ++ output[0] = a; ++ output[1] = d; ++ output[2] = b; ++ output[3] = e; ++ output[4] = c; ++ output[5] = f; ++ return; ++ } ++ ++ return [ ++ a, d, b, e, c, f // Specific format see LN:19 ++ ]; ++ ++ }, ++ ++ /** ++ * Clone the current matrix. ++ */ ++ clone: function() { ++ var a, b, c, d, e, f, g, h, i; ++ ++ a = this.elements[0]; ++ b = this.elements[1]; ++ c = this.elements[2]; ++ d = this.elements[3]; ++ e = this.elements[4]; ++ f = this.elements[5]; ++ g = this.elements[6]; ++ h = this.elements[7]; ++ i = this.elements[8]; ++ ++ return new Two.Matrix(a, b, c, d, e, f, g, h, i); ++ ++ } ++ ++ }); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ // Localize variables ++ var mod = Two.Utils.mod, toFixed = Two.Utils.toFixed; ++ var _ = Two.Utils; ++ ++ var svg = { ++ ++ version: 1.1, ++ ++ ns: 'http://www.w3.org/2000/svg', ++ xlink: 'http://www.w3.org/1999/xlink', ++ ++ alignments: { ++ left: 'start', ++ center: 'middle', ++ right: 'end' ++ }, ++ ++ /** ++ * Create an svg namespaced element. ++ */ ++ createElement: function(name, attrs) { ++ var tag = name; ++ var elem = document.createElementNS(svg.ns, tag); ++ if (tag === 'svg') { ++ attrs = _.defaults(attrs || {}, { ++ version: svg.version ++ }); ++ } ++ if (!_.isEmpty(attrs)) { ++ svg.setAttributes(elem, attrs); ++ } ++ return elem; ++ }, ++ ++ /** ++ * Add attributes from an svg element. ++ */ ++ setAttributes: function(elem, attrs) { ++ var keys = Object.keys(attrs); ++ for (var i = 0; i < keys.length; i++) { ++ if (/href/.test(keys[i])) { ++ elem.setAttributeNS(svg.xlink, keys[i], attrs[keys[i]]); ++ } else { ++ elem.setAttribute(keys[i], attrs[keys[i]]); ++ } ++ } ++ return this; ++ }, ++ ++ /** ++ * Remove attributes from an svg element. ++ */ ++ removeAttributes: function(elem, attrs) { ++ for (var key in attrs) { ++ elem.removeAttribute(key); ++ } ++ return this; ++ }, ++ ++ /** ++ * Turn a set of vertices into a string for the d property of a path ++ * element. It is imperative that the string collation is as fast as ++ * possible, because this call will be happening multiple times a ++ * second. ++ */ ++ toString: function(points, closed) { ++ ++ var l = points.length, ++ last = l - 1, ++ d, // The elusive last Two.Commands.move point ++ ret = ''; ++ ++ for (var i = 0; i < l; i++) { ++ var b = points[i]; ++ var command; ++ var prev = closed ? mod(i - 1, l) : Math.max(i - 1, 0); ++ var next = closed ? mod(i + 1, l) : Math.min(i + 1, last); ++ ++ var a = points[prev]; ++ var c = points[next]; ++ ++ var vx, vy, ux, uy, ar, bl, br, cl; ++ ++ // Access x and y directly, ++ // bypassing the getter ++ var x = toFixed(b._x); ++ var y = toFixed(b._y); ++ ++ switch (b._command) { ++ ++ case Two.Commands.close: ++ command = Two.Commands.close; ++ break; ++ ++ case Two.Commands.curve: ++ ++ ar = (a.controls && a.controls.right) || Two.Vector.zero; ++ bl = (b.controls && b.controls.left) || Two.Vector.zero; ++ ++ if (a._relative) { ++ vx = toFixed((ar.x + a.x)); ++ vy = toFixed((ar.y + a.y)); ++ } else { ++ vx = toFixed(ar.x); ++ vy = toFixed(ar.y); ++ } ++ ++ if (b._relative) { ++ ux = toFixed((bl.x + b.x)); ++ uy = toFixed((bl.y + b.y)); ++ } else { ++ ux = toFixed(bl.x); ++ uy = toFixed(bl.y); ++ } ++ ++ command = ((i === 0) ? Two.Commands.move : Two.Commands.curve) + ++ ' ' + vx + ' ' + vy + ' ' + ux + ' ' + uy + ' ' + x + ' ' + y; ++ break; ++ ++ case Two.Commands.move: ++ d = b; ++ command = Two.Commands.move + ' ' + x + ' ' + y; ++ break; ++ ++ default: ++ command = b._command + ' ' + x + ' ' + y; ++ ++ } ++ ++ // Add a final point and close it off ++ ++ if (i >= last && closed) { ++ ++ if (b._command === Two.Commands.curve) { ++ ++ // Make sure we close to the most previous Two.Commands.move ++ c = d; ++ ++ br = (b.controls && b.controls.right) || b; ++ cl = (c.controls && c.controls.left) || c; ++ ++ if (b._relative) { ++ vx = toFixed((br.x + b.x)); ++ vy = toFixed((br.y + b.y)); ++ } else { ++ vx = toFixed(br.x); ++ vy = toFixed(br.y); ++ } ++ ++ if (c._relative) { ++ ux = toFixed((cl.x + c.x)); ++ uy = toFixed((cl.y + c.y)); ++ } else { ++ ux = toFixed(cl.x); ++ uy = toFixed(cl.y); ++ } ++ ++ x = toFixed(c.x); ++ y = toFixed(c.y); ++ ++ command += ++ ' C ' + vx + ' ' + vy + ' ' + ux + ' ' + uy + ' ' + x + ' ' + y; ++ } ++ ++ command += ' Z'; ++ ++ } ++ ++ ret += command + ' '; ++ ++ } ++ ++ return ret; ++ ++ }, ++ ++ getClip: function(shape) { ++ ++ var clip = shape._renderer.clip; ++ ++ if (!clip) { ++ ++ var root = shape; ++ ++ while (root.parent) { ++ root = root.parent; ++ } ++ ++ clip = shape._renderer.clip = svg.createElement('clipPath'); ++ root.defs.appendChild(clip); ++ ++ } ++ ++ return clip; ++ ++ }, ++ ++ group: { ++ ++ // TODO: Can speed up. ++ // TODO: How does this effect a f ++ appendChild: function(object) { ++ ++ var elem = object._renderer.elem; ++ ++ if (!elem) { ++ return; ++ } ++ ++ var tag = elem.nodeName; ++ ++ if (!tag || /(radial|linear)gradient/i.test(tag) || object._clip) { ++ return; ++ } ++ ++ this.elem.appendChild(elem); ++ ++ }, ++ ++ removeChild: function(object) { ++ ++ var elem = object._renderer.elem; ++ ++ if (!elem || elem.parentNode != this.elem) { ++ return; ++ } ++ ++ var tag = elem.nodeName; ++ ++ if (!tag) { ++ return; ++ } ++ ++ // Defer subtractions while clipping. ++ if (object._clip) { ++ return; ++ } ++ ++ this.elem.removeChild(elem); ++ ++ }, ++ ++ orderChild: function(object) { ++ this.elem.appendChild(object._renderer.elem); ++ }, ++ ++ renderChild: function(child) { ++ svg[child._renderer.type].render.call(child, this); ++ }, ++ ++ render: function(domElement) { ++ ++ this._update(); ++ ++ // Shortcut for hidden objects. ++ // Doesn't reset the flags, so changes are stored and ++ // applied once the object is visible again ++ if (this._opacity === 0 && !this._flagOpacity) { ++ return this; ++ } ++ ++ if (!this._renderer.elem) { ++ this._renderer.elem = svg.createElement('g', { ++ id: this.id ++ }); ++ domElement.appendChild(this._renderer.elem); ++ } ++ ++ // _Update styles for the ++ var flagMatrix = this._matrix.manual || this._flagMatrix; ++ var context = { ++ domElement: domElement, ++ elem: this._renderer.elem ++ }; ++ ++ if (flagMatrix) { ++ this._renderer.elem.setAttribute('transform', 'matrix(' + this._matrix.toString() + ')'); ++ } ++ ++ for (var i = 0; i < this.children.length; i++) { ++ var child = this.children[i]; ++ svg[child._renderer.type].render.call(child, domElement); ++ } ++ ++ if (this._flagOpacity) { ++ this._renderer.elem.setAttribute('opacity', this._opacity); ++ } ++ ++ if (this._flagAdditions) { ++ this.additions.forEach(svg.group.appendChild, context); ++ } ++ ++ if (this._flagSubtractions) { ++ this.subtractions.forEach(svg.group.removeChild, context); ++ } ++ ++ if (this._flagOrder) { ++ this.children.forEach(svg.group.orderChild, context); ++ } ++ ++ /** ++ * Commented two-way functionality of clips / masks with groups and ++ * polygons. Uncomment when this bug is fixed: ++ * https://code.google.com/p/chromium/issues/detail?id=370951 ++ */ ++ ++ // if (this._flagClip) { ++ ++ // clip = svg.getClip(this); ++ // elem = this._renderer.elem; ++ ++ // if (this._clip) { ++ // elem.removeAttribute('id'); ++ // clip.setAttribute('id', this.id); ++ // clip.appendChild(elem); ++ // } else { ++ // clip.removeAttribute('id'); ++ // elem.setAttribute('id', this.id); ++ // this.parent._renderer.elem.appendChild(elem); // TODO: should be insertBefore ++ // } ++ ++ // } ++ ++ if (this._flagMask) { ++ if (this._mask) { ++ this._renderer.elem.setAttribute('clip-path', 'url(#' + this._mask.id + ')'); ++ } else { ++ this._renderer.elem.removeAttribute('clip-path'); ++ } ++ } ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ path: { ++ ++ render: function(domElement) { ++ ++ this._update(); ++ ++ // Shortcut for hidden objects. ++ // Doesn't reset the flags, so changes are stored and ++ // applied once the object is visible again ++ if (this._opacity === 0 && !this._flagOpacity) { ++ return this; ++ } ++ ++ // Collect any attribute that needs to be changed here ++ var changed = {}; ++ ++ var flagMatrix = this._matrix.manual || this._flagMatrix; ++ ++ if (flagMatrix) { ++ changed.transform = 'matrix(' + this._matrix.toString() + ')'; ++ } ++ ++ if (this._flagVertices) { ++ var vertices = svg.toString(this._vertices, this._closed); ++ changed.d = vertices; ++ } ++ ++ if (this._fill && this._fill._renderer) { ++ this._fill._update(); ++ svg[this._fill._renderer.type].render.call(this._fill, domElement, true); ++ } ++ ++ if (this._flagFill) { ++ changed.fill = this._fill && this._fill.id ++ ? 'url(#' + this._fill.id + ')' : this._fill; ++ } ++ ++ if (this._stroke && this._stroke._renderer) { ++ this._stroke._update(); ++ svg[this._stroke._renderer.type].render.call(this._stroke, domElement, true); ++ } ++ ++ if (this._flagStroke) { ++ changed.stroke = this._stroke && this._stroke.id ++ ? 'url(#' + this._stroke.id + ')' : this._stroke; ++ } ++ ++ if (this._flagLinewidth) { ++ changed['stroke-width'] = this._linewidth; ++ } ++ ++ if (this._flagOpacity) { ++ changed['stroke-opacity'] = this._opacity; ++ changed['fill-opacity'] = this._opacity; ++ } ++ ++ if (this._flagVisible) { ++ changed.visibility = this._visible ? 'visible' : 'hidden'; ++ } ++ ++ if (this._flagCap) { ++ changed['stroke-linecap'] = this._cap; ++ } ++ ++ if (this._flagJoin) { ++ changed['stroke-linejoin'] = this._join; ++ } ++ ++ if (this._flagMiter) { ++ changed['stroke-miterlimit'] = this._miter; ++ } ++ ++ // If there is no attached DOM element yet, ++ // create it with all necessary attributes. ++ if (!this._renderer.elem) { ++ ++ changed.id = this.id; ++ this._renderer.elem = svg.createElement('path', changed); ++ domElement.appendChild(this._renderer.elem); ++ ++ // Otherwise apply all pending attributes ++ } else { ++ svg.setAttributes(this._renderer.elem, changed); ++ } ++ ++ if (this._flagClip) { ++ ++ var clip = svg.getClip(this); ++ var elem = this._renderer.elem; ++ ++ if (this._clip) { ++ elem.removeAttribute('id'); ++ clip.setAttribute('id', this.id); ++ clip.appendChild(elem); ++ } else { ++ clip.removeAttribute('id'); ++ elem.setAttribute('id', this.id); ++ this.parent._renderer.elem.appendChild(elem); // TODO: should be insertBefore ++ } ++ ++ } ++ ++ /** ++ * Commented two-way functionality of clips / masks with groups and ++ * polygons. Uncomment when this bug is fixed: ++ * https://code.google.com/p/chromium/issues/detail?id=370951 ++ */ ++ ++ // if (this._flagMask) { ++ // if (this._mask) { ++ // elem.setAttribute('clip-path', 'url(#' + this._mask.id + ')'); ++ // } else { ++ // elem.removeAttribute('clip-path'); ++ // } ++ // } ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ text: { ++ ++ render: function(domElement) { ++ ++ this._update(); ++ ++ var changed = {}; ++ ++ var flagMatrix = this._matrix.manual || this._flagMatrix; ++ ++ if (flagMatrix) { ++ changed.transform = 'matrix(' + this._matrix.toString() + ')'; ++ } ++ ++ if (this._flagFamily) { ++ changed['font-family'] = this._family; ++ } ++ if (this._flagSize) { ++ changed['font-size'] = this._size; ++ } ++ if (this._flagLeading) { ++ changed['line-height'] = this._leading; ++ } ++ if (this._flagAlignment) { ++ changed['text-anchor'] = svg.alignments[this._alignment] || this._alignment; ++ } ++ if (this._flagBaseline) { ++ changed['alignment-baseline'] = changed['dominant-baseline'] = this._baseline; ++ } ++ if (this._flagStyle) { ++ changed['font-style'] = this._style; ++ } ++ if (this._flagWeight) { ++ changed['font-weight'] = this._weight; ++ } ++ if (this._flagDecoration) { ++ changed['text-decoration'] = this._decoration; ++ } ++ if (this._fill && this._fill._renderer) { ++ this._fill._update(); ++ svg[this._fill._renderer.type].render.call(this._fill, domElement, true); ++ } ++ if (this._flagFill) { ++ changed.fill = this._fill && this._fill.id ++ ? 'url(#' + this._fill.id + ')' : this._fill; ++ } ++ if (this._stroke && this._stroke._renderer) { ++ this._stroke._update(); ++ svg[this._stroke._renderer.type].render.call(this._stroke, domElement, true); ++ } ++ if (this._flagStroke) { ++ changed.stroke = this._stroke && this._stroke.id ++ ? 'url(#' + this._stroke.id + ')' : this._stroke; ++ } ++ if (this._flagLinewidth) { ++ changed['stroke-width'] = this._linewidth; ++ } ++ if (this._flagOpacity) { ++ changed.opacity = this._opacity; ++ } ++ if (this._flagVisible) { ++ changed.visibility = this._visible ? 'visible' : 'hidden'; ++ } ++ ++ if (!this._renderer.elem) { ++ ++ changed.id = this.id; ++ ++ this._renderer.elem = svg.createElement('text', changed); ++ domElement.defs.appendChild(this._renderer.elem); ++ ++ } else { ++ ++ svg.setAttributes(this._renderer.elem, changed); ++ ++ } ++ ++ if (this._flagClip) { ++ ++ var clip = svg.getClip(this); ++ var elem = this._renderer.elem; ++ ++ if (this._clip) { ++ elem.removeAttribute('id'); ++ clip.setAttribute('id', this.id); ++ clip.appendChild(elem); ++ } else { ++ clip.removeAttribute('id'); ++ elem.setAttribute('id', this.id); ++ this.parent._renderer.elem.appendChild(elem); // TODO: should be insertBefore ++ } ++ ++ } ++ ++ if (this._flagValue) { ++ this._renderer.elem.textContent = this._value; ++ } ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ 'linear-gradient': { ++ ++ render: function(domElement, silent) { ++ ++ if (!silent) { ++ this._update(); ++ } ++ ++ var changed = {}; ++ ++ if (this._flagEndPoints) { ++ changed.x1 = this.left._x; ++ changed.y1 = this.left._y; ++ changed.x2 = this.right._x; ++ changed.y2 = this.right._y; ++ } ++ ++ if (this._flagSpread) { ++ changed.spreadMethod = this._spread; ++ } ++ ++ // If there is no attached DOM element yet, ++ // create it with all necessary attributes. ++ if (!this._renderer.elem) { ++ ++ changed.id = this.id; ++ changed.gradientUnits = 'userSpaceOnUse'; ++ this._renderer.elem = svg.createElement('linearGradient', changed); ++ domElement.defs.appendChild(this._renderer.elem); ++ ++ // Otherwise apply all pending attributes ++ } else { ++ ++ svg.setAttributes(this._renderer.elem, changed); ++ ++ } ++ ++ if (this._flagStops) { ++ ++ var lengthChanged = this._renderer.elem.childNodes.length ++ !== this.stops.length; ++ ++ if (lengthChanged) { ++ this._renderer.elem.childNodes.length = 0; ++ } ++ ++ for (var i = 0; i < this.stops.length; i++) { ++ ++ var stop = this.stops[i]; ++ var attrs = {}; ++ ++ if (stop._flagOffset) { ++ attrs.offset = 100 * stop._offset + '%'; ++ } ++ if (stop._flagColor) { ++ attrs['stop-color'] = stop._color; ++ } ++ if (stop._flagOpacity) { ++ attrs['stop-opacity'] = stop._opacity; ++ } ++ ++ if (!stop._renderer.elem) { ++ stop._renderer.elem = svg.createElement('stop', attrs); ++ } else { ++ svg.setAttributes(stop._renderer.elem, attrs); ++ } ++ ++ if (lengthChanged) { ++ this._renderer.elem.appendChild(stop._renderer.elem); ++ } ++ stop.flagReset(); ++ ++ } ++ ++ } ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ 'radial-gradient': { ++ ++ render: function(domElement, silent) { ++ ++ if (!silent) { ++ this._update(); ++ } ++ ++ var changed = {}; ++ ++ if (this._flagCenter) { ++ changed.cx = this.center._x; ++ changed.cy = this.center._y; ++ } ++ if (this._flagFocal) { ++ changed.fx = this.focal._x; ++ changed.fy = this.focal._y; ++ } ++ ++ if (this._flagRadius) { ++ changed.r = this._radius; ++ } ++ ++ if (this._flagSpread) { ++ changed.spreadMethod = this._spread; ++ } ++ ++ // If there is no attached DOM element yet, ++ // create it with all necessary attributes. ++ if (!this._renderer.elem) { ++ ++ changed.id = this.id; ++ changed.gradientUnits = 'userSpaceOnUse'; ++ this._renderer.elem = svg.createElement('radialGradient', changed); ++ domElement.defs.appendChild(this._renderer.elem); ++ ++ // Otherwise apply all pending attributes ++ } else { ++ ++ svg.setAttributes(this._renderer.elem, changed); ++ ++ } ++ ++ if (this._flagStops) { ++ ++ var lengthChanged = this._renderer.elem.childNodes.length ++ !== this.stops.length; ++ ++ if (lengthChanged) { ++ this._renderer.elem.childNodes.length = 0; ++ } ++ ++ for (var i = 0; i < this.stops.length; i++) { ++ ++ var stop = this.stops[i]; ++ var attrs = {}; ++ ++ if (stop._flagOffset) { ++ attrs.offset = 100 * stop._offset + '%'; ++ } ++ if (stop._flagColor) { ++ attrs['stop-color'] = stop._color; ++ } ++ if (stop._flagOpacity) { ++ attrs['stop-opacity'] = stop._opacity; ++ } ++ ++ if (!stop._renderer.elem) { ++ stop._renderer.elem = svg.createElement('stop', attrs); ++ } else { ++ svg.setAttributes(stop._renderer.elem, attrs); ++ } ++ ++ if (lengthChanged) { ++ this._renderer.elem.appendChild(stop._renderer.elem); ++ } ++ stop.flagReset(); ++ ++ } ++ ++ } ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ texture: { ++ ++ render: function(domElement, silent) { ++ ++ if (!silent) { ++ this._update(); ++ } ++ ++ var changed = {}; ++ var styles = { x: 0, y: 0 }; ++ var image = this.image; ++ ++ if (this._flagLoaded && this.loaded) { ++ ++ switch (image.nodeName.toLowerCase()) { ++ ++ case 'canvas': ++ styles.href = styles['xlink:href'] = image.toDataURL('image/png'); ++ break; ++ case 'img': ++ case 'image': ++ styles.href = styles['xlink:href'] = this.src; ++ break; ++ ++ } ++ ++ } ++ ++ if (this._flagOffset || this._flagLoaded || this._flagScale) { ++ ++ changed.x = this._offset.x; ++ changed.y = this._offset.y; ++ ++ if (image) { ++ ++ changed.x -= image.width / 2; ++ changed.y -= image.height / 2; ++ ++ if (this._scale instanceof Two.Vector) { ++ changed.x *= this._scale.x; ++ changed.y *= this._scale.y; ++ } else { ++ changed.x *= this._scale; ++ changed.y *= this._scale; ++ } ++ } ++ ++ if (changed.x > 0) { ++ changed.x *= - 1; ++ } ++ if (changed.y > 0) { ++ changed.y *= - 1; ++ } ++ ++ } ++ ++ if (this._flagScale || this._flagLoaded || this._flagRepeat) { ++ ++ changed.width = 0; ++ changed.height = 0; ++ ++ if (image) { ++ ++ styles.width = changed.width = image.width; ++ styles.height = changed.height = image.height; ++ ++ // TODO: Hack / Bandaid ++ switch (this._repeat) { ++ case 'no-repeat': ++ changed.width += 1; ++ changed.height += 1; ++ break; ++ } ++ ++ if (this._scale instanceof Two.Vector) { ++ changed.width *= this._scale.x; ++ changed.height *= this._scale.y; ++ } else { ++ changed.width *= this._scale; ++ changed.height *= this._scale; ++ } ++ } ++ ++ } ++ ++ if (this._flagScale || this._flagLoaded) { ++ if (!this._renderer.image) { ++ this._renderer.image = svg.createElement('image', styles); ++ } else if (!_.isEmpty(styles)) { ++ svg.setAttributes(this._renderer.image, styles); ++ } ++ } ++ ++ if (!this._renderer.elem) { ++ ++ changed.id = this.id; ++ changed.patternUnits = 'userSpaceOnUse'; ++ this._renderer.elem = svg.createElement('pattern', changed); ++ domElement.defs.appendChild(this._renderer.elem); ++ ++ } else if (!_.isEmpty(changed)) { ++ ++ svg.setAttributes(this._renderer.elem, changed); ++ ++ } ++ ++ if (this._renderer.elem && this._renderer.image && !this._renderer.appended) { ++ this._renderer.elem.appendChild(this._renderer.image); ++ this._renderer.appended = true; ++ } ++ ++ return this.flagReset(); ++ ++ } ++ ++ } ++ ++ }; ++ ++ /** ++ * @class ++ */ ++ var Renderer = Two[Two.Types.svg] = function(params) { ++ ++ this.domElement = params.domElement || svg.createElement('svg'); ++ ++ this.scene = new Two.Group(); ++ this.scene.parent = this; ++ ++ this.defs = svg.createElement('defs'); ++ this.domElement.appendChild(this.defs); ++ this.domElement.defs = this.defs; ++ this.domElement.style.overflow = 'hidden'; ++ ++ }; ++ ++ _.extend(Renderer, { ++ ++ Utils: svg ++ ++ }); ++ ++ _.extend(Renderer.prototype, Two.Utils.Events, { ++ ++ setSize: function(width, height) { ++ ++ this.width = width; ++ this.height = height; ++ ++ svg.setAttributes(this.domElement, { ++ width: width, ++ height: height ++ }); ++ ++ return this; ++ ++ }, ++ ++ render: function() { ++ ++ svg.group.render.call(this.scene, this.domElement); ++ ++ return this; ++ ++ } ++ ++ }); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ /** ++ * Constants ++ */ ++ var mod = Two.Utils.mod, toFixed = Two.Utils.toFixed; ++ var getRatio = Two.Utils.getRatio; ++ var _ = Two.Utils; ++ ++ // Returns true if this is a non-transforming matrix ++ var isDefaultMatrix = function (m) { ++ return (m[0] == 1 && m[3] == 0 && m[1] == 0 && m[4] == 1 && m[2] == 0 && m[5] == 0); ++ }; ++ ++ var canvas = { ++ ++ isHidden: /(none|transparent)/i, ++ ++ alignments: { ++ left: 'start', ++ middle: 'center', ++ right: 'end' ++ }, ++ ++ shim: function(elem) { ++ elem.tagName = 'canvas'; ++ elem.nodeType = 1; ++ return elem; ++ }, ++ ++ group: { ++ ++ renderChild: function(child) { ++ canvas[child._renderer.type].render.call(child, this.ctx, true, this.clip); ++ }, ++ ++ render: function(ctx) { ++ ++ // TODO: Add a check here to only invoke _update if need be. ++ this._update(); ++ ++ var matrix = this._matrix.elements; ++ var parent = this.parent; ++ this._renderer.opacity = this._opacity * (parent && parent._renderer ? parent._renderer.opacity : 1); ++ ++ var defaultMatrix = isDefaultMatrix(matrix); ++ ++ var mask = this._mask; ++ // var clip = this._clip; ++ ++ if (!this._renderer.context) { ++ this._renderer.context = {}; ++ } ++ ++ this._renderer.context.ctx = ctx; ++ // this._renderer.context.clip = clip; ++ ++ if (!defaultMatrix) { ++ ctx.save(); ++ ctx.transform(matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]); ++ } ++ ++ if (mask) { ++ canvas[mask._renderer.type].render.call(mask, ctx, true); ++ } ++ ++ if (this.opacity > 0 && this.scale !== 0) { ++ for (var i = 0; i < this.children.length; i++) { ++ var child = this.children[i]; ++ canvas[child._renderer.type].render.call(child, ctx); ++ } ++ } ++ ++ if (!defaultMatrix) { ++ ctx.restore(); ++ } ++ ++ /** ++ * Commented two-way functionality of clips / masks with groups and ++ * polygons. Uncomment when this bug is fixed: ++ * https://code.google.com/p/chromium/issues/detail?id=370951 ++ */ ++ ++ // if (clip) { ++ // ctx.clip(); ++ // } ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ path: { ++ ++ render: function(ctx, forced, parentClipped) { ++ ++ var matrix, stroke, linewidth, fill, opacity, visible, cap, join, miter, ++ closed, commands, length, last, next, prev, a, b, c, d, ux, uy, vx, vy, ++ ar, bl, br, cl, x, y, mask, clip, defaultMatrix, isOffset; ++ ++ // TODO: Add a check here to only invoke _update if need be. ++ this._update(); ++ ++ matrix = this._matrix.elements; ++ stroke = this._stroke; ++ linewidth = this._linewidth; ++ fill = this._fill; ++ opacity = this._opacity * this.parent._renderer.opacity; ++ visible = this._visible; ++ cap = this._cap; ++ join = this._join; ++ miter = this._miter; ++ closed = this._closed; ++ commands = this._vertices; // Commands ++ length = commands.length; ++ last = length - 1; ++ defaultMatrix = isDefaultMatrix(matrix); ++ ++ // mask = this._mask; ++ clip = this._clip; ++ ++ if (!forced && (!visible || clip)) { ++ return this; ++ } ++ ++ // Transform ++ if (!defaultMatrix) { ++ ctx.save(); ++ ctx.transform(matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]); ++ } ++ ++ /** ++ * Commented two-way functionality of clips / masks with groups and ++ * polygons. Uncomment when this bug is fixed: ++ * https://code.google.com/p/chromium/issues/detail?id=370951 ++ */ ++ ++ // if (mask) { ++ // canvas[mask._renderer.type].render.call(mask, ctx, true); ++ // } ++ ++ // Styles ++ if (fill) { ++ if (_.isString(fill)) { ++ ctx.fillStyle = fill; ++ } else { ++ canvas[fill._renderer.type].render.call(fill, ctx); ++ ctx.fillStyle = fill._renderer.effect; ++ } ++ } ++ if (stroke) { ++ if (_.isString(stroke)) { ++ ctx.strokeStyle = stroke; ++ } else { ++ canvas[stroke._renderer.type].render.call(stroke, ctx); ++ ctx.strokeStyle = stroke._renderer.effect; ++ } ++ } ++ if (linewidth) { ++ ctx.lineWidth = linewidth; ++ } ++ if (miter) { ++ ctx.miterLimit = miter; ++ } ++ if (join) { ++ ctx.lineJoin = join; ++ } ++ if (cap) { ++ ctx.lineCap = cap; ++ } ++ if (_.isNumber(opacity)) { ++ ctx.globalAlpha = opacity; ++ } ++ ++ ctx.beginPath(); ++ ++ for (var i = 0; i < commands.length; i++) { ++ ++ b = commands[i]; ++ ++ x = toFixed(b._x); ++ y = toFixed(b._y); ++ ++ switch (b._command) { ++ ++ case Two.Commands.close: ++ ctx.closePath(); ++ break; ++ ++ case Two.Commands.curve: ++ ++ prev = closed ? mod(i - 1, length) : Math.max(i - 1, 0); ++ next = closed ? mod(i + 1, length) : Math.min(i + 1, last); ++ ++ a = commands[prev]; ++ c = commands[next]; ++ ar = (a.controls && a.controls.right) || Two.Vector.zero; ++ bl = (b.controls && b.controls.left) || Two.Vector.zero; ++ ++ if (a._relative) { ++ vx = (ar.x + toFixed(a._x)); ++ vy = (ar.y + toFixed(a._y)); ++ } else { ++ vx = toFixed(ar.x); ++ vy = toFixed(ar.y); ++ } ++ ++ if (b._relative) { ++ ux = (bl.x + toFixed(b._x)); ++ uy = (bl.y + toFixed(b._y)); ++ } else { ++ ux = toFixed(bl.x); ++ uy = toFixed(bl.y); ++ } ++ ++ ctx.bezierCurveTo(vx, vy, ux, uy, x, y); ++ ++ if (i >= last && closed) { ++ ++ c = d; ++ ++ br = (b.controls && b.controls.right) || Two.Vector.zero; ++ cl = (c.controls && c.controls.left) || Two.Vector.zero; ++ ++ if (b._relative) { ++ vx = (br.x + toFixed(b._x)); ++ vy = (br.y + toFixed(b._y)); ++ } else { ++ vx = toFixed(br.x); ++ vy = toFixed(br.y); ++ } ++ ++ if (c._relative) { ++ ux = (cl.x + toFixed(c._x)); ++ uy = (cl.y + toFixed(c._y)); ++ } else { ++ ux = toFixed(cl.x); ++ uy = toFixed(cl.y); ++ } ++ ++ x = toFixed(c._x); ++ y = toFixed(c._y); ++ ++ ctx.bezierCurveTo(vx, vy, ux, uy, x, y); ++ ++ } ++ ++ break; ++ ++ case Two.Commands.line: ++ ctx.lineTo(x, y); ++ break; ++ ++ case Two.Commands.move: ++ d = b; ++ ctx.moveTo(x, y); ++ break; ++ ++ } ++ } ++ ++ // Loose ends ++ ++ if (closed) { ++ ctx.closePath(); ++ } ++ ++ if (!clip && !parentClipped) { ++ if (!canvas.isHidden.test(fill)) { ++ isOffset = fill._renderer && fill._renderer.offset ++ if (isOffset) { ++ ctx.save(); ++ ctx.translate( ++ - fill._renderer.offset.x, - fill._renderer.offset.y); ++ ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y); ++ } ++ ctx.fill(); ++ if (isOffset) { ++ ctx.restore(); ++ } ++ } ++ if (!canvas.isHidden.test(stroke)) { ++ isOffset = stroke._renderer && stroke._renderer.offset; ++ if (isOffset) { ++ ctx.save(); ++ ctx.translate( ++ - stroke._renderer.offset.x, - stroke._renderer.offset.y); ++ ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y); ++ ctx.lineWidth = linewidth / stroke._renderer.scale.x; ++ } ++ ctx.stroke(); ++ if (isOffset) { ++ ctx.restore(); ++ } ++ } ++ } ++ ++ if (!defaultMatrix) { ++ ctx.restore(); ++ } ++ ++ if (clip && !parentClipped) { ++ ctx.clip(); ++ } ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ text: { ++ ++ render: function(ctx, forced, parentClipped) { ++ ++ // TODO: Add a check here to only invoke _update if need be. ++ this._update(); ++ ++ var matrix = this._matrix.elements; ++ var stroke = this._stroke; ++ var linewidth = this._linewidth; ++ var fill = this._fill; ++ var opacity = this._opacity * this.parent._renderer.opacity; ++ var visible = this._visible; ++ var defaultMatrix = isDefaultMatrix(matrix); ++ var isOffset = fill._renderer && fill._renderer.offset ++ && stroke._renderer && stroke._renderer.offset; ++ ++ var a, b, c, d, e, sx, sy; ++ ++ // mask = this._mask; ++ var clip = this._clip; ++ ++ if (!forced && (!visible || clip)) { ++ return this; ++ } ++ ++ // Transform ++ if (!defaultMatrix) { ++ ctx.save(); ++ ctx.transform(matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]); ++ } ++ ++ /** ++ * Commented two-way functionality of clips / masks with groups and ++ * polygons. Uncomment when this bug is fixed: ++ * https://code.google.com/p/chromium/issues/detail?id=370951 ++ */ ++ ++ // if (mask) { ++ // canvas[mask._renderer.type].render.call(mask, ctx, true); ++ // } ++ ++ if (!isOffset) { ++ ctx.font = [this._style, this._weight, this._size + 'px/' + ++ this._leading + 'px', this._family].join(' '); ++ } ++ ++ ctx.textAlign = canvas.alignments[this._alignment] || this._alignment; ++ ctx.textBaseline = this._baseline; ++ ++ // Styles ++ if (fill) { ++ if (_.isString(fill)) { ++ ctx.fillStyle = fill; ++ } else { ++ canvas[fill._renderer.type].render.call(fill, ctx); ++ ctx.fillStyle = fill._renderer.effect; ++ } ++ } ++ if (stroke) { ++ if (_.isString(stroke)) { ++ ctx.strokeStyle = stroke; ++ } else { ++ canvas[stroke._renderer.type].render.call(stroke, ctx); ++ ctx.strokeStyle = stroke._renderer.effect; ++ } ++ } ++ if (linewidth) { ++ ctx.lineWidth = linewidth; ++ } ++ if (_.isNumber(opacity)) { ++ ctx.globalAlpha = opacity; ++ } ++ ++ if (!clip && !parentClipped) { ++ ++ if (!canvas.isHidden.test(fill)) { ++ ++ if (fill._renderer && fill._renderer.offset) { ++ ++ sx = toFixed(fill._renderer.scale.x); ++ sy = toFixed(fill._renderer.scale.y); ++ ++ ctx.save(); ++ ctx.translate( - toFixed(fill._renderer.offset.x), ++ - toFixed(fill._renderer.offset.y)); ++ ctx.scale(sx, sy); ++ ++ a = this._size / fill._renderer.scale.y; ++ b = this._leading / fill._renderer.scale.y; ++ ctx.font = [this._style, this._weight, toFixed(a) + 'px/', ++ toFixed(b) + 'px', this._family].join(' '); ++ ++ c = fill._renderer.offset.x / fill._renderer.scale.x; ++ d = fill._renderer.offset.y / fill._renderer.scale.y; ++ ++ ctx.fillText(this.value, toFixed(c), toFixed(d)); ++ ctx.restore(); ++ ++ } else { ++ ctx.fillText(this.value, 0, 0); ++ } ++ ++ } ++ ++ if (!canvas.isHidden.test(stroke)) { ++ ++ if (stroke._renderer && stroke._renderer.offset) { ++ ++ sx = toFixed(stroke._renderer.scale.x); ++ sy = toFixed(stroke._renderer.scale.y); ++ ++ ctx.save(); ++ ctx.translate(- toFixed(stroke._renderer.offset.x), ++ - toFixed(stroke._renderer.offset.y)); ++ ctx.scale(sx, sy); ++ ++ a = this._size / stroke._renderer.scale.y; ++ b = this._leading / stroke._renderer.scale.y; ++ ctx.font = [this._style, this._weight, toFixed(a) + 'px/', ++ toFixed(b) + 'px', this._family].join(' '); ++ ++ c = stroke._renderer.offset.x / stroke._renderer.scale.x; ++ d = stroke._renderer.offset.y / stroke._renderer.scale.y; ++ e = linewidth / stroke._renderer.scale.x; ++ ++ ctx.lineWidth = toFixed(e); ++ ctx.strokeText(this.value, toFixed(c), toFixed(d)); ++ ctx.restore(); ++ ++ } else { ++ ctx.strokeText(this.value, 0, 0); ++ } ++ } ++ } ++ ++ if (!defaultMatrix) { ++ ctx.restore(); ++ } ++ ++ // TODO: Test for text ++ if (clip && !parentClipped) { ++ ctx.clip(); ++ } ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ 'linear-gradient': { ++ ++ render: function(ctx) { ++ ++ this._update(); ++ ++ if (!this._renderer.effect || this._flagEndPoints || this._flagStops) { ++ ++ this._renderer.effect = ctx.createLinearGradient( ++ this.left._x, this.left._y, ++ this.right._x, this.right._y ++ ); ++ ++ for (var i = 0; i < this.stops.length; i++) { ++ var stop = this.stops[i]; ++ this._renderer.effect.addColorStop(stop._offset, stop._color); ++ } ++ ++ } ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ 'radial-gradient': { ++ ++ render: function(ctx) { ++ ++ this._update(); ++ ++ if (!this._renderer.effect || this._flagCenter || this._flagFocal ++ || this._flagRadius || this._flagStops) { ++ ++ this._renderer.effect = ctx.createRadialGradient( ++ this.center._x, this.center._y, 0, ++ this.focal._x, this.focal._y, this._radius ++ ); ++ ++ for (var i = 0; i < this.stops.length; i++) { ++ var stop = this.stops[i]; ++ this._renderer.effect.addColorStop(stop._offset, stop._color); ++ } ++ ++ } ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ texture: { ++ ++ render: function(ctx) { ++ ++ this._update(); ++ ++ var image = this.image; ++ var repeat; ++ ++ if (!this._renderer.effect || ((this._flagLoaded || this._flagImage || this._flagVideo || this._flagRepeat) && this.loaded)) { ++ this._renderer.effect = ctx.createPattern(this.image, this._repeat); ++ } ++ ++ if (this._flagOffset || this._flagLoaded || this._flagScale) { ++ ++ if (!(this._renderer.offset instanceof Two.Vector)) { ++ this._renderer.offset = new Two.Vector(); ++ } ++ ++ this._renderer.offset.x = - this._offset.x; ++ this._renderer.offset.y = - this._offset.y; ++ ++ if (image) { ++ ++ this._renderer.offset.x += image.width / 2; ++ this._renderer.offset.y += image.height / 2; ++ ++ if (this._scale instanceof Two.Vector) { ++ this._renderer.offset.x *= this._scale.x; ++ this._renderer.offset.y *= this._scale.y; ++ } else { ++ this._renderer.offset.x *= this._scale; ++ this._renderer.offset.y *= this._scale; ++ } ++ } ++ ++ } ++ ++ if (this._flagScale || this._flagLoaded) { ++ ++ if (!(this._renderer.scale instanceof Two.Vector)) { ++ this._renderer.scale = new Two.Vector(); ++ } ++ ++ if (this._scale instanceof Two.Vector) { ++ this._renderer.scale.copy(this._scale); ++ } else { ++ this._renderer.scale.set(this._scale, this._scale); ++ } ++ ++ } ++ ++ return this.flagReset(); ++ ++ } ++ ++ } ++ ++ }; ++ ++ var Renderer = Two[Two.Types.canvas] = function(params) { ++ // Smoothing property. Defaults to true ++ // Set it to false when working with pixel art. ++ // false can lead to better performance, since it would use a cheaper interpolation algorithm. ++ // It might not make a big difference on GPU backed canvases. ++ var smoothing = (params.smoothing !== false); ++ this.domElement = params.domElement || document.createElement('canvas'); ++ this.ctx = this.domElement.getContext('2d'); ++ this.overdraw = params.overdraw || false; ++ ++ if (!_.isUndefined(this.ctx.imageSmoothingEnabled)) { ++ this.ctx.imageSmoothingEnabled = smoothing; ++ } ++ ++ // Everything drawn on the canvas needs to be added to the scene. ++ this.scene = new Two.Group(); ++ this.scene.parent = this; ++ }; ++ ++ ++ _.extend(Renderer, { ++ ++ Utils: canvas ++ ++ }); ++ ++ _.extend(Renderer.prototype, Two.Utils.Events, { ++ ++ setSize: function(width, height, ratio) { ++ ++ this.width = width; ++ this.height = height; ++ ++ this.ratio = _.isUndefined(ratio) ? getRatio(this.ctx) : ratio; ++ ++ this.domElement.width = width * this.ratio; ++ this.domElement.height = height * this.ratio; ++ ++ if (this.domElement.style) { ++ _.extend(this.domElement.style, { ++ width: width + 'px', ++ height: height + 'px' ++ }); ++ } ++ ++ return this; ++ ++ }, ++ ++ render: function() { ++ ++ var isOne = this.ratio === 1; ++ ++ if (!isOne) { ++ this.ctx.save(); ++ this.ctx.scale(this.ratio, this.ratio); ++ } ++ ++ if (!this.overdraw) { ++ this.ctx.clearRect(0, 0, this.width, this.height); ++ } ++ ++ canvas.group.render.call(this.scene, this.ctx); ++ ++ if (!isOne) { ++ this.ctx.restore(); ++ } ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ function resetTransform(ctx) { ++ ctx.setTransform(1, 0, 0, 1, 0, 0); ++ } ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ /** ++ * Constants ++ */ ++ ++ var root = Two.root, ++ multiplyMatrix = Two.Matrix.Multiply, ++ mod = Two.Utils.mod, ++ identity = [1, 0, 0, 0, 1, 0, 0, 0, 1], ++ transformation = new Two.Array(9), ++ getRatio = Two.Utils.getRatio, ++ getComputedMatrix = Two.Utils.getComputedMatrix, ++ toFixed = Two.Utils.toFixed, ++ _ = Two.Utils; ++ ++ var webgl = { ++ ++ isHidden: /(none|transparent)/i, ++ ++ canvas: (root.document ? root.document.createElement('canvas') : { getContext: _.identity }), ++ ++ alignments: { ++ left: 'start', ++ middle: 'center', ++ right: 'end' ++ }, ++ ++ matrix: new Two.Matrix(), ++ ++ uv: new Two.Array([ ++ 0, 0, ++ 1, 0, ++ 0, 1, ++ 0, 1, ++ 1, 0, ++ 1, 1 ++ ]), ++ ++ group: { ++ ++ removeChild: function(child, gl) { ++ if (child.children) { ++ for (var i = 0; i < child.children.length; i++) { ++ webgl.group.removeChild(child.children[i], gl); ++ } ++ return; ++ } ++ // Deallocate texture to free up gl memory. ++ gl.deleteTexture(child._renderer.texture); ++ delete child._renderer.texture; ++ }, ++ ++ renderChild: function(child) { ++ webgl[child._renderer.type].render.call(child, this.gl, this.program); ++ }, ++ ++ render: function(gl, program) { ++ ++ this._update(); ++ ++ var parent = this.parent; ++ var flagParentMatrix = (parent._matrix && parent._matrix.manual) || parent._flagMatrix; ++ var flagMatrix = this._matrix.manual || this._flagMatrix; ++ ++ if (flagParentMatrix || flagMatrix) { ++ ++ if (!this._renderer.matrix) { ++ this._renderer.matrix = new Two.Array(9); ++ } ++ ++ // Reduce amount of object / array creation / deletion ++ this._matrix.toArray(true, transformation); ++ ++ multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix); ++ this._renderer.scale = this._scale * parent._renderer.scale; ++ ++ if (flagParentMatrix) { ++ this._flagMatrix = true; ++ } ++ ++ } ++ ++ if (this._mask) { ++ ++ gl.enable(gl.STENCIL_TEST); ++ gl.stencilFunc(gl.ALWAYS, 1, 1); ++ ++ gl.colorMask(false, false, false, true); ++ gl.stencilOp(gl.KEEP, gl.KEEP, gl.INCR); ++ ++ webgl[this._mask._renderer.type].render.call(this._mask, gl, program, this); ++ ++ gl.colorMask(true, true, true, true); ++ gl.stencilFunc(gl.NOTEQUAL, 0, 1); ++ gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); ++ ++ } ++ ++ this._flagOpacity = parent._flagOpacity || this._flagOpacity; ++ ++ this._renderer.opacity = this._opacity ++ * (parent && parent._renderer ? parent._renderer.opacity : 1); ++ ++ if (this._flagSubtractions) { ++ for (var i = 0; i < this.subtractions.length; i++) { ++ webgl.group.removeChild(this.subtractions[i], gl); ++ } ++ } ++ ++ this.children.forEach(webgl.group.renderChild, { ++ gl: gl, ++ program: program ++ }); ++ ++ if (this._mask) { ++ ++ gl.colorMask(false, false, false, false); ++ gl.stencilOp(gl.KEEP, gl.KEEP, gl.DECR); ++ ++ webgl[this._mask._renderer.type].render.call(this._mask, gl, program, this); ++ ++ gl.colorMask(true, true, true, true); ++ gl.stencilFunc(gl.NOTEQUAL, 0, 1); ++ gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); ++ ++ gl.disable(gl.STENCIL_TEST); ++ ++ } ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ path: { ++ ++ updateCanvas: function(elem) { ++ ++ var next, prev, a, c, ux, uy, vx, vy, ar, bl, br, cl, x, y; ++ var isOffset; ++ ++ var commands = elem._vertices; ++ var canvas = this.canvas; ++ var ctx = this.ctx; ++ ++ // Styles ++ var scale = elem._renderer.scale; ++ var stroke = elem._stroke; ++ var linewidth = elem._linewidth; ++ var fill = elem._fill; ++ var opacity = elem._renderer.opacity || elem._opacity; ++ var cap = elem._cap; ++ var join = elem._join; ++ var miter = elem._miter; ++ var closed = elem._closed; ++ var length = commands.length; ++ var last = length - 1; ++ ++ canvas.width = Math.max(Math.ceil(elem._renderer.rect.width * scale), 1); ++ canvas.height = Math.max(Math.ceil(elem._renderer.rect.height * scale), 1); ++ ++ var centroid = elem._renderer.rect.centroid; ++ var cx = centroid.x; ++ var cy = centroid.y; ++ ++ ctx.clearRect(0, 0, canvas.width, canvas.height); ++ ++ if (fill) { ++ if (_.isString(fill)) { ++ ctx.fillStyle = fill; ++ } else { ++ webgl[fill._renderer.type].render.call(fill, ctx, elem); ++ ctx.fillStyle = fill._renderer.effect; ++ } ++ } ++ if (stroke) { ++ if (_.isString(stroke)) { ++ ctx.strokeStyle = stroke; ++ } else { ++ webgl[stroke._renderer.type].render.call(stroke, ctx, elem); ++ ctx.strokeStyle = stroke._renderer.effect; ++ } ++ } ++ if (linewidth) { ++ ctx.lineWidth = linewidth; ++ } ++ if (miter) { ++ ctx.miterLimit = miter; ++ } ++ if (join) { ++ ctx.lineJoin = join; ++ } ++ if (cap) { ++ ctx.lineCap = cap; ++ } ++ if (_.isNumber(opacity)) { ++ ctx.globalAlpha = opacity; ++ } ++ ++ var d; ++ ctx.save(); ++ ctx.scale(scale, scale); ++ ctx.translate(cx, cy); ++ ++ ctx.beginPath(); ++ for (var i = 0; i < commands.length; i++) { ++ ++ b = commands[i]; ++ ++ x = toFixed(b._x); ++ y = toFixed(b._y); ++ ++ switch (b._command) { ++ ++ case Two.Commands.close: ++ ctx.closePath(); ++ break; ++ ++ case Two.Commands.curve: ++ ++ prev = closed ? mod(i - 1, length) : Math.max(i - 1, 0); ++ next = closed ? mod(i + 1, length) : Math.min(i + 1, last); ++ ++ a = commands[prev]; ++ c = commands[next]; ++ ar = (a.controls && a.controls.right) || Two.Vector.zero; ++ bl = (b.controls && b.controls.left) || Two.Vector.zero; ++ ++ if (a._relative) { ++ vx = toFixed((ar.x + a._x)); ++ vy = toFixed((ar.y + a._y)); ++ } else { ++ vx = toFixed(ar.x); ++ vy = toFixed(ar.y); ++ } ++ ++ if (b._relative) { ++ ux = toFixed((bl.x + b._x)); ++ uy = toFixed((bl.y + b._y)); ++ } else { ++ ux = toFixed(bl.x); ++ uy = toFixed(bl.y); ++ } ++ ++ ctx.bezierCurveTo(vx, vy, ux, uy, x, y); ++ ++ if (i >= last && closed) { ++ ++ c = d; ++ ++ br = (b.controls && b.controls.right) || Two.Vector.zero; ++ cl = (c.controls && c.controls.left) || Two.Vector.zero; ++ ++ if (b._relative) { ++ vx = toFixed((br.x + b._x)); ++ vy = toFixed((br.y + b._y)); ++ } else { ++ vx = toFixed(br.x); ++ vy = toFixed(br.y); ++ } ++ ++ if (c._relative) { ++ ux = toFixed((cl.x + c._x)); ++ uy = toFixed((cl.y + c._y)); ++ } else { ++ ux = toFixed(cl.x); ++ uy = toFixed(cl.y); ++ } ++ ++ x = toFixed(c._x); ++ y = toFixed(c._y); ++ ++ ctx.bezierCurveTo(vx, vy, ux, uy, x, y); ++ ++ } ++ ++ break; ++ ++ case Two.Commands.line: ++ ctx.lineTo(x, y); ++ break; ++ ++ case Two.Commands.move: ++ d = b; ++ ctx.moveTo(x, y); ++ break; ++ ++ } ++ ++ } ++ ++ // Loose ends ++ ++ if (closed) { ++ ctx.closePath(); ++ } ++ ++ if (!webgl.isHidden.test(fill)) { ++ isOffset = fill._renderer && fill._renderer.offset ++ if (isOffset) { ++ ctx.save(); ++ ctx.translate( ++ - fill._renderer.offset.x, - fill._renderer.offset.y); ++ ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y); ++ } ++ ctx.fill(); ++ if (isOffset) { ++ ctx.restore(); ++ } ++ } ++ ++ if (!webgl.isHidden.test(stroke)) { ++ isOffset = stroke._renderer && stroke._renderer.offset; ++ if (isOffset) { ++ ctx.save(); ++ ctx.translate( ++ - stroke._renderer.offset.x, - stroke._renderer.offset.y); ++ ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y); ++ ctx.lineWidth = linewidth / stroke._renderer.scale.x; ++ } ++ ctx.stroke(); ++ if (isOffset) { ++ ctx.restore(); ++ } ++ } ++ ++ ctx.restore(); ++ ++ }, ++ ++ /** ++ * Returns the rect of a set of verts. Typically takes vertices that are ++ * "centered" around 0 and returns them to be anchored upper-left. ++ */ ++ getBoundingClientRect: function(vertices, border, rect) { ++ ++ var left = Infinity, right = -Infinity, ++ top = Infinity, bottom = -Infinity, ++ width, height; ++ ++ vertices.forEach(function(v) { ++ ++ var x = v.x, y = v.y, controls = v.controls; ++ var a, b, c, d, cl, cr; ++ ++ top = Math.min(y, top); ++ left = Math.min(x, left); ++ right = Math.max(x, right); ++ bottom = Math.max(y, bottom); ++ ++ if (!v.controls) { ++ return; ++ } ++ ++ cl = controls.left; ++ cr = controls.right; ++ ++ if (!cl || !cr) { ++ return; ++ } ++ ++ a = v._relative ? cl.x + x : cl.x; ++ b = v._relative ? cl.y + y : cl.y; ++ c = v._relative ? cr.x + x : cr.x; ++ d = v._relative ? cr.y + y : cr.y; ++ ++ if (!a || !b || !c || !d) { ++ return; ++ } ++ ++ top = Math.min(b, d, top); ++ left = Math.min(a, c, left); ++ right = Math.max(a, c, right); ++ bottom = Math.max(b, d, bottom); ++ ++ }); ++ ++ // Expand borders ++ ++ if (_.isNumber(border)) { ++ top -= border; ++ left -= border; ++ right += border; ++ bottom += border; ++ } ++ ++ width = right - left; ++ height = bottom - top; ++ ++ rect.top = top; ++ rect.left = left; ++ rect.right = right; ++ rect.bottom = bottom; ++ rect.width = width; ++ rect.height = height; ++ ++ if (!rect.centroid) { ++ rect.centroid = {}; ++ } ++ ++ rect.centroid.x = - left; ++ rect.centroid.y = - top; ++ ++ }, ++ ++ render: function(gl, program, forcedParent) { ++ ++ if (!this._visible || !this._opacity) { ++ return this; ++ } ++ ++ this._update(); ++ ++ // Calculate what changed ++ ++ var parent = this.parent; ++ var flagParentMatrix = parent._matrix.manual || parent._flagMatrix; ++ var flagMatrix = this._matrix.manual || this._flagMatrix; ++ var flagTexture = this._flagVertices || this._flagFill ++ || (this._fill instanceof Two.LinearGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagEndPoints)) ++ || (this._fill instanceof Two.RadialGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagRadius || this._fill._flagCenter || this._fill._flagFocal)) ++ || (this._fill instanceof Two.Texture && (this._fill._flagLoaded && this._fill.loaded || this._fill._flagOffset || this._fill._flagScale)) ++ || (this._stroke instanceof Two.LinearGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagEndPoints)) ++ || (this._stroke instanceof Two.RadialGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagRadius || this._stroke._flagCenter || this._stroke._flagFocal)) ++ || (this._stroke instanceof Two.Texture && (this._stroke._flagLoaded && this._stroke.loaded || this._stroke._flagOffset || this._fill._flagScale)) ++ || this._flagStroke || this._flagLinewidth || this._flagOpacity ++ || parent._flagOpacity || this._flagVisible || this._flagCap ++ || this._flagJoin || this._flagMiter || this._flagScale ++ || !this._renderer.texture; ++ ++ if (flagParentMatrix || flagMatrix) { ++ ++ if (!this._renderer.matrix) { ++ this._renderer.matrix = new Two.Array(9); ++ } ++ ++ // Reduce amount of object / array creation / deletion ++ ++ this._matrix.toArray(true, transformation); ++ ++ multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix); ++ this._renderer.scale = this._scale * parent._renderer.scale; ++ ++ } ++ ++ if (flagTexture) { ++ ++ if (!this._renderer.rect) { ++ this._renderer.rect = {}; ++ } ++ ++ if (!this._renderer.triangles) { ++ this._renderer.triangles = new Two.Array(12); ++ } ++ ++ this._renderer.opacity = this._opacity * parent._renderer.opacity; ++ ++ webgl.path.getBoundingClientRect(this._vertices, this._linewidth, this._renderer.rect); ++ webgl.getTriangles(this._renderer.rect, this._renderer.triangles); ++ ++ webgl.updateBuffer.call(webgl, gl, this, program); ++ webgl.updateTexture.call(webgl, gl, this); ++ ++ } ++ ++ // if (this._mask) { ++ // webgl[this._mask._renderer.type].render.call(mask, gl, program, this); ++ // } ++ ++ if (this._clip && !forcedParent) { ++ return; ++ } ++ ++ // Draw Texture ++ ++ gl.bindBuffer(gl.ARRAY_BUFFER, this._renderer.textureCoordsBuffer); ++ ++ gl.vertexAttribPointer(program.textureCoords, 2, gl.FLOAT, false, 0, 0); ++ ++ gl.bindTexture(gl.TEXTURE_2D, this._renderer.texture); ++ ++ ++ // Draw Rect ++ ++ gl.uniformMatrix3fv(program.matrix, false, this._renderer.matrix); ++ ++ gl.bindBuffer(gl.ARRAY_BUFFER, this._renderer.buffer); ++ ++ gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0); ++ ++ gl.drawArrays(gl.TRIANGLES, 0, 6); ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ text: { ++ ++ updateCanvas: function(elem) { ++ ++ var canvas = this.canvas; ++ var ctx = this.ctx; ++ ++ // Styles ++ var scale = elem._renderer.scale; ++ var stroke = elem._stroke; ++ var linewidth = elem._linewidth * scale; ++ var fill = elem._fill; ++ var opacity = elem._renderer.opacity || elem._opacity; ++ ++ canvas.width = Math.max(Math.ceil(elem._renderer.rect.width * scale), 1); ++ canvas.height = Math.max(Math.ceil(elem._renderer.rect.height * scale), 1); ++ ++ var centroid = elem._renderer.rect.centroid; ++ var cx = centroid.x; ++ var cy = centroid.y; ++ ++ var a, b, c, d, e, sx, sy; ++ var isOffset = fill._renderer && fill._renderer.offset ++ && stroke._renderer && stroke._renderer.offset; ++ ++ ctx.clearRect(0, 0, canvas.width, canvas.height); ++ ++ if (!isOffset) { ++ ctx.font = [elem._style, elem._weight, elem._size + 'px/' + ++ elem._leading + 'px', elem._family].join(' '); ++ } ++ ++ ctx.textAlign = 'center'; ++ ctx.textBaseline = 'middle'; ++ ++ // Styles ++ if (fill) { ++ if (_.isString(fill)) { ++ ctx.fillStyle = fill; ++ } else { ++ webgl[fill._renderer.type].render.call(fill, ctx, elem); ++ ctx.fillStyle = fill._renderer.effect; ++ } ++ } ++ if (stroke) { ++ if (_.isString(stroke)) { ++ ctx.strokeStyle = stroke; ++ } else { ++ webgl[stroke._renderer.type].render.call(stroke, ctx, elem); ++ ctx.strokeStyle = stroke._renderer.effect; ++ } ++ } ++ if (linewidth) { ++ ctx.lineWidth = linewidth; ++ } ++ if (_.isNumber(opacity)) { ++ ctx.globalAlpha = opacity; ++ } ++ ++ ctx.save(); ++ ctx.scale(scale, scale); ++ ctx.translate(cx, cy); ++ ++ if (!webgl.isHidden.test(fill)) { ++ ++ if (fill._renderer && fill._renderer.offset) { ++ ++ sx = toFixed(fill._renderer.scale.x); ++ sy = toFixed(fill._renderer.scale.y); ++ ++ ctx.save(); ++ ctx.translate( - toFixed(fill._renderer.offset.x), ++ - toFixed(fill._renderer.offset.y)); ++ ctx.scale(sx, sy); ++ ++ a = elem._size / fill._renderer.scale.y; ++ b = elem._leading / fill._renderer.scale.y; ++ ctx.font = [elem._style, elem._weight, toFixed(a) + 'px/', ++ toFixed(b) + 'px', elem._family].join(' '); ++ ++ c = fill._renderer.offset.x / fill._renderer.scale.x; ++ d = fill._renderer.offset.y / fill._renderer.scale.y; ++ ++ ctx.fillText(elem.value, toFixed(c), toFixed(d)); ++ ctx.restore(); ++ ++ } else { ++ ctx.fillText(elem.value, 0, 0); ++ } ++ ++ } ++ ++ if (!webgl.isHidden.test(stroke)) { ++ ++ if (stroke._renderer && stroke._renderer.offset) { ++ ++ sx = toFixed(stroke._renderer.scale.x); ++ sy = toFixed(stroke._renderer.scale.y); ++ ++ ctx.save(); ++ ctx.translate(- toFixed(stroke._renderer.offset.x), ++ - toFixed(stroke._renderer.offset.y)); ++ ctx.scale(sx, sy); ++ ++ a = elem._size / stroke._renderer.scale.y; ++ b = elem._leading / stroke._renderer.scale.y; ++ ctx.font = [elem._style, elem._weight, toFixed(a) + 'px/', ++ toFixed(b) + 'px', elem._family].join(' '); ++ ++ c = stroke._renderer.offset.x / stroke._renderer.scale.x; ++ d = stroke._renderer.offset.y / stroke._renderer.scale.y; ++ e = linewidth / stroke._renderer.scale.x; ++ ++ ctx.lineWidth = toFixed(e); ++ ctx.strokeText(elem.value, toFixed(c), toFixed(d)); ++ ctx.restore(); ++ ++ } else { ++ ctx.strokeText(elem.value, 0, 0); ++ } ++ ++ } ++ ++ ctx.restore(); ++ ++ }, ++ ++ getBoundingClientRect: function(elem, rect) { ++ ++ var ctx = webgl.ctx; ++ ++ ctx.font = [elem._style, elem._weight, elem._size + 'px/' + ++ elem._leading + 'px', elem._family].join(' '); ++ ++ ctx.textAlign = 'center'; ++ ctx.textBaseline = elem._baseline; ++ ++ // TODO: Estimate this better ++ var width = ctx.measureText(elem._value).width; ++ var height = Math.max(elem._size || elem._leading); ++ ++ if (this._linewidth && !webgl.isHidden.test(this._stroke)) { ++ // width += this._linewidth; // TODO: Not sure if the `measure` calcs this. ++ height += this._linewidth; ++ } ++ ++ var w = width / 2; ++ var h = height / 2; ++ ++ switch (webgl.alignments[elem._alignment] || elem._alignment) { ++ ++ case webgl.alignments.left: ++ rect.left = 0; ++ rect.right = width; ++ break; ++ case webgl.alignments.right: ++ rect.left = - width; ++ rect.right = 0; ++ break; ++ default: ++ rect.left = - w; ++ rect.right = w; ++ } ++ ++ // TODO: Gradients aren't inherited... ++ switch (elem._baseline) { ++ case 'bottom': ++ rect.top = - height; ++ rect.bottom = 0; ++ break; ++ case 'top': ++ rect.top = 0; ++ rect.bottom = height; ++ break; ++ default: ++ rect.top = - h; ++ rect.bottom = h; ++ } ++ ++ rect.width = width; ++ rect.height = height; ++ ++ if (!rect.centroid) { ++ rect.centroid = {}; ++ } ++ ++ // TODO: ++ rect.centroid.x = w; ++ rect.centroid.y = h; ++ ++ }, ++ ++ render: function(gl, program, forcedParent) { ++ ++ if (!this._visible || !this._opacity) { ++ return this; ++ } ++ ++ this._update(); ++ ++ // Calculate what changed ++ ++ var parent = this.parent; ++ var flagParentMatrix = parent._matrix.manual || parent._flagMatrix; ++ var flagMatrix = this._matrix.manual || this._flagMatrix; ++ var flagTexture = this._flagVertices || this._flagFill ++ || (this._fill instanceof Two.LinearGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagEndPoints)) ++ || (this._fill instanceof Two.RadialGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagRadius || this._fill._flagCenter || this._fill._flagFocal)) ++ || (this._fill instanceof Two.Texture && (this._fill._flagLoaded && this._fill.loaded)) ++ || (this._stroke instanceof Two.LinearGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagEndPoints)) ++ || (this._stroke instanceof Two.RadialGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagRadius || this._stroke._flagCenter || this._stroke._flagFocal)) ++ || (this._texture instanceof Two.Texture && (this._texture._flagLoaded && this._texture.loaded)) ++ || this._flagStroke || this._flagLinewidth || this._flagOpacity ++ || parent._flagOpacity || this._flagVisible || this._flagScale ++ || this._flagValue || this._flagFamily || this._flagSize ++ || this._flagLeading || this._flagAlignment || this._flagBaseline ++ || this._flagStyle || this._flagWeight || this._flagDecoration ++ || !this._renderer.texture; ++ ++ if (flagParentMatrix || flagMatrix) { ++ ++ if (!this._renderer.matrix) { ++ this._renderer.matrix = new Two.Array(9); ++ } ++ ++ // Reduce amount of object / array creation / deletion ++ ++ this._matrix.toArray(true, transformation); ++ ++ multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix); ++ this._renderer.scale = this._scale * parent._renderer.scale; ++ ++ } ++ ++ if (flagTexture) { ++ ++ if (!this._renderer.rect) { ++ this._renderer.rect = {}; ++ } ++ ++ if (!this._renderer.triangles) { ++ this._renderer.triangles = new Two.Array(12); ++ } ++ ++ this._renderer.opacity = this._opacity * parent._renderer.opacity; ++ ++ webgl.text.getBoundingClientRect(this, this._renderer.rect); ++ webgl.getTriangles(this._renderer.rect, this._renderer.triangles); ++ ++ webgl.updateBuffer.call(webgl, gl, this, program); ++ webgl.updateTexture.call(webgl, gl, this); ++ ++ } ++ ++ // if (this._mask) { ++ // webgl[this._mask._renderer.type].render.call(mask, gl, program, this); ++ // } ++ ++ if (this._clip && !forcedParent) { ++ return; ++ } ++ ++ // Draw Texture ++ ++ gl.bindBuffer(gl.ARRAY_BUFFER, this._renderer.textureCoordsBuffer); ++ ++ gl.vertexAttribPointer(program.textureCoords, 2, gl.FLOAT, false, 0, 0); ++ ++ gl.bindTexture(gl.TEXTURE_2D, this._renderer.texture); ++ ++ ++ // Draw Rect ++ ++ gl.uniformMatrix3fv(program.matrix, false, this._renderer.matrix); ++ ++ gl.bindBuffer(gl.ARRAY_BUFFER, this._renderer.buffer); ++ ++ gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0); ++ ++ gl.drawArrays(gl.TRIANGLES, 0, 6); ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ 'linear-gradient': { ++ ++ render: function(ctx, elem) { ++ ++ if (!ctx.canvas.getContext('2d')) { ++ return; ++ } ++ ++ this._update(); ++ ++ if (!this._renderer.effect || this._flagEndPoints || this._flagStops) { ++ ++ this._renderer.effect = ctx.createLinearGradient( ++ this.left._x, this.left._y, ++ this.right._x, this.right._y ++ ); ++ ++ for (var i = 0; i < this.stops.length; i++) { ++ var stop = this.stops[i]; ++ this._renderer.effect.addColorStop(stop._offset, stop._color); ++ } ++ ++ } ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ 'radial-gradient': { ++ ++ render: function(ctx, elem) { ++ ++ if (!ctx.canvas.getContext('2d')) { ++ return; ++ } ++ ++ this._update(); ++ ++ if (!this._renderer.effect || this._flagCenter || this._flagFocal ++ || this._flagRadius || this._flagStops) { ++ ++ this._renderer.effect = ctx.createRadialGradient( ++ this.center._x, this.center._y, 0, ++ this.focal._x, this.focal._y, this._radius ++ ); ++ ++ for (var i = 0; i < this.stops.length; i++) { ++ var stop = this.stops[i]; ++ this._renderer.effect.addColorStop(stop._offset, stop._color); ++ } ++ ++ } ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ texture: { ++ ++ render: function(ctx, elem) { ++ ++ if (!ctx.canvas.getContext('2d')) { ++ return; ++ } ++ ++ this._update(); ++ ++ var image = this.image; ++ var repeat; ++ ++ if (!this._renderer.effect || ((this._flagLoaded || this._flagRepeat) && this.loaded)) { ++ this._renderer.effect = ctx.createPattern(image, this._repeat); ++ } ++ ++ if (this._flagOffset || this._flagLoaded || this._flagScale) { ++ ++ if (!(this._renderer.offset instanceof Two.Vector)) { ++ this._renderer.offset = new Two.Vector(); ++ } ++ ++ this._renderer.offset.x = this._offset.x; ++ this._renderer.offset.y = this._offset.y; ++ ++ if (image) { ++ ++ this._renderer.offset.x -= image.width / 2; ++ this._renderer.offset.y += image.height / 2; ++ ++ if (this._scale instanceof Two.Vector) { ++ this._renderer.offset.x *= this._scale.x; ++ this._renderer.offset.y *= this._scale.y; ++ } else { ++ this._renderer.offset.x *= this._scale; ++ this._renderer.offset.y *= this._scale; ++ } ++ } ++ ++ } ++ ++ if (this._flagScale || this._flagLoaded) { ++ ++ if (!(this._renderer.scale instanceof Two.Vector)) { ++ this._renderer.scale = new Two.Vector(); ++ } ++ ++ if (this._scale instanceof Two.Vector) { ++ this._renderer.scale.copy(this._scale); ++ } else { ++ this._renderer.scale.set(this._scale, this._scale); ++ } ++ ++ } ++ ++ return this.flagReset(); ++ ++ } ++ ++ }, ++ ++ getTriangles: function(rect, triangles) { ++ ++ var top = rect.top, ++ left = rect.left, ++ right = rect.right, ++ bottom = rect.bottom; ++ ++ // First Triangle ++ ++ triangles[0] = left; ++ triangles[1] = top; ++ ++ triangles[2] = right; ++ triangles[3] = top; ++ ++ triangles[4] = left; ++ triangles[5] = bottom; ++ ++ // Second Triangle ++ ++ triangles[6] = left; ++ triangles[7] = bottom; ++ ++ triangles[8] = right; ++ triangles[9] = top; ++ ++ triangles[10] = right; ++ triangles[11] = bottom; ++ ++ }, ++ ++ updateTexture: function(gl, elem) { ++ ++ this[elem._renderer.type].updateCanvas.call(webgl, elem); ++ ++ if (elem._renderer.texture) { ++ gl.deleteTexture(elem._renderer.texture); ++ } ++ ++ gl.bindBuffer(gl.ARRAY_BUFFER, elem._renderer.textureCoordsBuffer); ++ ++ // TODO: Is this necessary every time or can we do once? ++ // TODO: Create a registry for textures ++ elem._renderer.texture = gl.createTexture(); ++ gl.bindTexture(gl.TEXTURE_2D, elem._renderer.texture); ++ ++ // Set the parameters so we can render any size image. ++ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); ++ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); ++ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); ++ // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); ++ // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); ++ // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); ++ ++ if (this.canvas.width <= 0 || this.canvas.height <= 0) { ++ return; ++ } ++ ++ // Upload the image into the texture. ++ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.canvas); ++ ++ }, ++ ++ updateBuffer: function(gl, elem, program) { ++ ++ if (_.isObject(elem._renderer.buffer)) { ++ gl.deleteBuffer(elem._renderer.buffer); ++ } ++ ++ elem._renderer.buffer = gl.createBuffer(); ++ ++ gl.bindBuffer(gl.ARRAY_BUFFER, elem._renderer.buffer); ++ gl.enableVertexAttribArray(program.position); ++ ++ gl.bufferData(gl.ARRAY_BUFFER, elem._renderer.triangles, gl.STATIC_DRAW); ++ ++ if (_.isObject(elem._renderer.textureCoordsBuffer)) { ++ gl.deleteBuffer(elem._renderer.textureCoordsBuffer); ++ } ++ ++ elem._renderer.textureCoordsBuffer = gl.createBuffer(); ++ ++ gl.bindBuffer(gl.ARRAY_BUFFER, elem._renderer.textureCoordsBuffer); ++ gl.enableVertexAttribArray(program.textureCoords); ++ ++ gl.bufferData(gl.ARRAY_BUFFER, this.uv, gl.STATIC_DRAW); ++ ++ }, ++ ++ program: { ++ ++ create: function(gl, shaders) { ++ var program, linked, error; ++ program = gl.createProgram(); ++ _.each(shaders, function(s) { ++ gl.attachShader(program, s); ++ }); ++ ++ gl.linkProgram(program); ++ linked = gl.getProgramParameter(program, gl.LINK_STATUS); ++ if (!linked) { ++ error = gl.getProgramInfoLog(program); ++ gl.deleteProgram(program); ++ throw new Two.Utils.Error('unable to link program: ' + error); ++ } ++ ++ return program; ++ ++ } ++ ++ }, ++ ++ shaders: { ++ ++ create: function(gl, source, type) { ++ var shader, compiled, error; ++ shader = gl.createShader(gl[type]); ++ gl.shaderSource(shader, source); ++ gl.compileShader(shader); ++ ++ compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); ++ if (!compiled) { ++ error = gl.getShaderInfoLog(shader); ++ gl.deleteShader(shader); ++ throw new Two.Utils.Error('unable to compile shader ' + shader + ': ' + error); ++ } ++ ++ return shader; ++ ++ }, ++ ++ types: { ++ vertex: 'VERTEX_SHADER', ++ fragment: 'FRAGMENT_SHADER' ++ }, ++ ++ vertex: [ ++ 'attribute vec2 a_position;', ++ 'attribute vec2 a_textureCoords;', ++ '', ++ 'uniform mat3 u_matrix;', ++ 'uniform vec2 u_resolution;', ++ '', ++ 'varying vec2 v_textureCoords;', ++ '', ++ 'void main() {', ++ ' vec2 projected = (u_matrix * vec3(a_position, 1.0)).xy;', ++ ' vec2 normal = projected / u_resolution;', ++ ' vec2 clipspace = (normal * 2.0) - 1.0;', ++ '', ++ ' gl_Position = vec4(clipspace * vec2(1.0, -1.0), 0.0, 1.0);', ++ ' v_textureCoords = a_textureCoords;', ++ '}' ++ ].join('\n'), ++ ++ fragment: [ ++ 'precision mediump float;', ++ '', ++ 'uniform sampler2D u_image;', ++ 'varying vec2 v_textureCoords;', ++ '', ++ 'void main() {', ++ ' gl_FragColor = texture2D(u_image, v_textureCoords);', ++ '}' ++ ].join('\n') ++ ++ }, ++ ++ TextureRegistry: new Two.Registry() ++ ++ }; ++ ++ webgl.ctx = webgl.canvas.getContext('2d'); ++ ++ var Renderer = Two[Two.Types.webgl] = function(options) { ++ ++ var params, gl, vs, fs; ++ this.domElement = options.domElement || document.createElement('canvas'); ++ ++ // Everything drawn on the canvas needs to come from the stage. ++ this.scene = new Two.Group(); ++ this.scene.parent = this; ++ ++ this._renderer = { ++ matrix: new Two.Array(identity), ++ scale: 1, ++ opacity: 1 ++ }; ++ this._flagMatrix = true; ++ ++ // http://games.greggman.com/game/webgl-and-alpha/ ++ // http://www.khronos.org/registry/webgl/specs/latest/#5.2 ++ params = _.defaults(options || {}, { ++ antialias: false, ++ alpha: true, ++ premultipliedAlpha: true, ++ stencil: true, ++ preserveDrawingBuffer: true, ++ overdraw: false ++ }); ++ ++ this.overdraw = params.overdraw; ++ ++ gl = this.ctx = this.domElement.getContext('webgl', params) || ++ this.domElement.getContext('experimental-webgl', params); ++ ++ if (!this.ctx) { ++ throw new Two.Utils.Error( ++ 'unable to create a webgl context. Try using another renderer.'); ++ } ++ ++ // Compile Base Shaders to draw in pixel space. ++ vs = webgl.shaders.create( ++ gl, webgl.shaders.vertex, webgl.shaders.types.vertex); ++ fs = webgl.shaders.create( ++ gl, webgl.shaders.fragment, webgl.shaders.types.fragment); ++ ++ this.program = webgl.program.create(gl, [vs, fs]); ++ gl.useProgram(this.program); ++ ++ // Create and bind the drawing buffer ++ ++ // look up where the vertex data needs to go. ++ this.program.position = gl.getAttribLocation(this.program, 'a_position'); ++ this.program.matrix = gl.getUniformLocation(this.program, 'u_matrix'); ++ this.program.textureCoords = gl.getAttribLocation(this.program, 'a_textureCoords'); ++ ++ // Copied from Three.js WebGLRenderer ++ gl.disable(gl.DEPTH_TEST); ++ ++ // Setup some initial statements of the gl context ++ gl.enable(gl.BLEND); ++ ++ // https://code.google.com/p/chromium/issues/detail?id=316393 ++ // gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, gl.TRUE); ++ ++ gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD); ++ gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, ++ gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); ++ ++ }; ++ ++ _.extend(Renderer, { ++ ++ Utils: webgl ++ ++ }); ++ ++ _.extend(Renderer.prototype, Two.Utils.Events, { ++ ++ setSize: function(width, height, ratio) { ++ ++ this.width = width; ++ this.height = height; ++ ++ this.ratio = _.isUndefined(ratio) ? getRatio(this.ctx) : ratio; ++ ++ this.domElement.width = width * this.ratio; ++ this.domElement.height = height * this.ratio; ++ ++ _.extend(this.domElement.style, { ++ width: width + 'px', ++ height: height + 'px' ++ }); ++ ++ width *= this.ratio; ++ height *= this.ratio; ++ ++ // Set for this.stage parent scaling to account for HDPI ++ this._renderer.matrix[0] = this._renderer.matrix[4] = this._renderer.scale = this.ratio; ++ ++ this._flagMatrix = true; ++ ++ this.ctx.viewport(0, 0, width, height); ++ ++ var resolutionLocation = this.ctx.getUniformLocation( ++ this.program, 'u_resolution'); ++ this.ctx.uniform2f(resolutionLocation, width, height); ++ ++ return this; ++ ++ }, ++ ++ render: function() { ++ ++ var gl = this.ctx; ++ ++ if (!this.overdraw) { ++ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); ++ } ++ ++ webgl.group.render.call(this.scene, gl, this.program); ++ this._flagMatrix = false; ++ ++ return this; ++ ++ } ++ ++ }); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var _ = Two.Utils; ++ ++ var Shape = Two.Shape = function() { ++ ++ // Private object for renderer specific variables. ++ this._renderer = {}; ++ this._renderer.flagMatrix = _.bind(Shape.FlagMatrix, this); ++ this.isShape = true; ++ ++ this.id = Two.Identifier + Two.uniqueId(); ++ this.classList = []; ++ ++ // Define matrix properties which all inherited ++ // objects of Shape have. ++ ++ this._matrix = new Two.Matrix(); ++ ++ this.translation = new Two.Vector(); ++ this.rotation = 0; ++ this.scale = 1; ++ ++ }; ++ ++ _.extend(Shape, { ++ ++ FlagMatrix: function() { ++ this._flagMatrix = true; ++ }, ++ ++ MakeObservable: function(object) { ++ ++ Object.defineProperty(object, 'translation', { ++ enumerable: true, ++ get: function() { ++ return this._translation; ++ }, ++ set: function(v) { ++ if (this._translation) { ++ this._translation.unbind(Two.Events.change, this._renderer.flagMatrix); ++ } ++ this._translation = v; ++ this._translation.bind(Two.Events.change, this._renderer.flagMatrix); ++ Shape.FlagMatrix.call(this); ++ } ++ }); ++ ++ Object.defineProperty(object, 'rotation', { ++ enumerable: true, ++ get: function() { ++ return this._rotation; ++ }, ++ set: function(v) { ++ this._rotation = v; ++ this._flagMatrix = true; ++ } ++ }); ++ ++ Object.defineProperty(object, 'scale', { ++ enumerable: true, ++ get: function() { ++ return this._scale; ++ }, ++ set: function(v) { ++ ++ if (this._scale instanceof Two.Vector) { ++ this._scale.unbind(Two.Events.change, this._renderer.flagMatrix); ++ } ++ ++ this._scale = v; ++ ++ if (this._scale instanceof Two.Vector) { ++ this._scale.bind(Two.Events.change, this._renderer.flagMatrix); ++ } ++ ++ this._flagMatrix = true; ++ this._flagScale = true; ++ ++ } ++ }); ++ ++ } ++ ++ }); ++ ++ _.extend(Shape.prototype, Two.Utils.Events, { ++ ++ // Flags ++ ++ _flagMatrix: true, ++ _flagScale: false, ++ ++ // _flagMask: false, ++ // _flagClip: false, ++ ++ // Underlying Properties ++ ++ _rotation: 0, ++ _scale: 1, ++ _translation: null, ++ ++ // _mask: null, ++ // _clip: false, ++ ++ addTo: function(group) { ++ group.add(this); ++ return this; ++ }, ++ ++ clone: function() { ++ var clone = new Shape(); ++ clone.translation.copy(this.translation); ++ clone.rotation = this.rotation; ++ clone.scale = this.scale; ++ _.each(Shape.Properties, function(k) { ++ clone[k] = this[k]; ++ }, this); ++ return clone._update(); ++ }, ++ ++ /** ++ * To be called before render that calculates and collates all information ++ * to be as up-to-date as possible for the render. Called once a frame. ++ */ ++ _update: function(deep) { ++ ++ if (!this._matrix.manual && this._flagMatrix) { ++ ++ this._matrix ++ .identity() ++ .translate(this.translation.x, this.translation.y); ++ ++ if (this._scale instanceof Two.Vector) { ++ this._matrix.scale(this._scale.x, this._scale.y); ++ } else { ++ this._matrix.scale(this._scale); ++ } ++ ++ this._matrix.rotate(this.rotation); ++ ++ } ++ ++ if (deep) { ++ // Bubble up to parents mainly for `getBoundingClientRect` method. ++ if (this.parent && this.parent._update) { ++ this.parent._update(); ++ } ++ } ++ ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagMatrix = this._flagScale = false; ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ Shape.MakeObservable(Shape.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ /** ++ * Constants ++ */ ++ ++ var min = Math.min, max = Math.max, round = Math.round, ++ getComputedMatrix = Two.Utils.getComputedMatrix; ++ ++ var commands = {}; ++ var _ = Two.Utils; ++ ++ _.each(Two.Commands, function(v, k) { ++ commands[k] = new RegExp(v); ++ }); ++ ++ var Path = Two.Path = function(vertices, closed, curved, manual) { ++ ++ Two.Shape.call(this); ++ ++ this._renderer.type = 'path'; ++ this._renderer.flagVertices = _.bind(Path.FlagVertices, this); ++ this._renderer.bindVertices = _.bind(Path.BindVertices, this); ++ this._renderer.unbindVertices = _.bind(Path.UnbindVertices, this); ++ ++ this._renderer.flagFill = _.bind(Path.FlagFill, this); ++ this._renderer.flagStroke = _.bind(Path.FlagStroke, this); ++ ++ this._closed = !!closed; ++ this._curved = !!curved; ++ ++ this.beginning = 0; ++ this.ending = 1; ++ ++ // Style properties ++ ++ this.fill = '#fff'; ++ this.stroke = '#000'; ++ this.linewidth = 1.0; ++ this.opacity = 1.0; ++ this.visible = true; ++ ++ this.cap = 'butt'; // Default of Adobe Illustrator ++ this.join = 'miter'; // Default of Adobe Illustrator ++ this.miter = 4; // Default of Adobe Illustrator ++ ++ this._vertices = []; ++ this.vertices = vertices; ++ ++ // Determines whether or not two.js should calculate curves, lines, and ++ // commands automatically for you or to let the developer manipulate them ++ // for themselves. ++ this.automatic = !manual; ++ ++ }; ++ ++ _.extend(Path, { ++ ++ Properties: [ ++ 'fill', ++ 'stroke', ++ 'linewidth', ++ 'opacity', ++ 'visible', ++ 'cap', ++ 'join', ++ 'miter', ++ ++ 'closed', ++ 'curved', ++ 'automatic', ++ 'beginning', ++ 'ending' ++ ], ++ ++ FlagVertices: function() { ++ this._flagVertices = true; ++ this._flagLength = true; ++ }, ++ ++ BindVertices: function(items) { ++ ++ // This function is called a lot ++ // when importing a large SVG ++ var i = items.length; ++ while (i--) { ++ items[i].bind(Two.Events.change, this._renderer.flagVertices); ++ } ++ ++ this._renderer.flagVertices(); ++ ++ }, ++ ++ UnbindVertices: function(items) { ++ ++ var i = items.length; ++ while (i--) { ++ items[i].unbind(Two.Events.change, this._renderer.flagVertices); ++ } ++ ++ this._renderer.flagVertices(); ++ ++ }, ++ ++ FlagFill: function() { ++ this._flagFill = true; ++ }, ++ ++ FlagStroke: function() { ++ this._flagStroke = true; ++ }, ++ ++ MakeObservable: function(object) { ++ ++ Two.Shape.MakeObservable(object); ++ ++ // Only the 6 defined properties are flagged like this. The subsequent ++ // properties behave differently and need to be hand written. ++ _.each(Path.Properties.slice(2, 8), Two.Utils.defineProperty, object); ++ ++ Object.defineProperty(object, 'fill', { ++ enumerable: true, ++ get: function() { ++ return this._fill; ++ }, ++ set: function(f) { ++ ++ if (this._fill instanceof Two.Gradient ++ || this._fill instanceof Two.LinearGradient ++ || this._fill instanceof Two.RadialGradient ++ || this._fill instanceof Two.Texture) { ++ this._fill.unbind(Two.Events.change, this._renderer.flagFill); ++ } ++ ++ this._fill = f; ++ this._flagFill = true; ++ ++ if (this._fill instanceof Two.Gradient ++ || this._fill instanceof Two.LinearGradient ++ || this._fill instanceof Two.RadialGradient ++ || this._fill instanceof Two.Texture) { ++ this._fill.bind(Two.Events.change, this._renderer.flagFill); ++ } ++ ++ } ++ }); ++ ++ Object.defineProperty(object, 'stroke', { ++ enumerable: true, ++ get: function() { ++ return this._stroke; ++ }, ++ set: function(f) { ++ ++ if (this._stroke instanceof Two.Gradient ++ || this._stroke instanceof Two.LinearGradient ++ || this._stroke instanceof Two.RadialGradient ++ || this._stroke instanceof Two.Texture) { ++ this._stroke.unbind(Two.Events.change, this._renderer.flagStroke); ++ } ++ ++ this._stroke = f; ++ this._flagStroke = true; ++ ++ if (this._stroke instanceof Two.Gradient ++ || this._stroke instanceof Two.LinearGradient ++ || this._stroke instanceof Two.RadialGradient ++ || this._stroke instanceof Two.Texture) { ++ this._stroke.bind(Two.Events.change, this._renderer.flagStroke); ++ } ++ ++ } ++ }); ++ ++ Object.defineProperty(object, 'length', { ++ get: function() { ++ if (this._flagLength) { ++ this._updateLength(); ++ } ++ return this._length; ++ } ++ }); ++ ++ Object.defineProperty(object, 'closed', { ++ enumerable: true, ++ get: function() { ++ return this._closed; ++ }, ++ set: function(v) { ++ this._closed = !!v; ++ this._flagVertices = true; ++ } ++ }); ++ ++ Object.defineProperty(object, 'curved', { ++ enumerable: true, ++ get: function() { ++ return this._curved; ++ }, ++ set: function(v) { ++ this._curved = !!v; ++ this._flagVertices = true; ++ } ++ }); ++ ++ Object.defineProperty(object, 'automatic', { ++ enumerable: true, ++ get: function() { ++ return this._automatic; ++ }, ++ set: function(v) { ++ if (v === this._automatic) { ++ return; ++ } ++ this._automatic = !!v; ++ var method = this._automatic ? 'ignore' : 'listen'; ++ _.each(this.vertices, function(v) { ++ v[method](); ++ }); ++ } ++ }); ++ ++ Object.defineProperty(object, 'beginning', { ++ enumerable: true, ++ get: function() { ++ return this._beginning; ++ }, ++ set: function(v) { ++ this._beginning = v; ++ this._flagVertices = true; ++ } ++ }); ++ ++ Object.defineProperty(object, 'ending', { ++ enumerable: true, ++ get: function() { ++ return this._ending; ++ }, ++ set: function(v) { ++ this._ending = v; ++ this._flagVertices = true; ++ } ++ }); ++ ++ Object.defineProperty(object, 'vertices', { ++ ++ enumerable: true, ++ ++ get: function() { ++ return this._collection; ++ }, ++ ++ set: function(vertices) { ++ ++ var updateVertices = this._renderer.flagVertices; ++ var bindVertices = this._renderer.bindVertices; ++ var unbindVertices = this._renderer.unbindVertices; ++ ++ // Remove previous listeners ++ if (this._collection) { ++ this._collection ++ .unbind(Two.Events.insert, bindVertices) ++ .unbind(Two.Events.remove, unbindVertices); ++ } ++ ++ // Create new Collection with copy of vertices ++ this._collection = new Two.Utils.Collection((vertices || []).slice(0)); ++ ++ // Listen for Collection changes and bind / unbind ++ this._collection ++ .bind(Two.Events.insert, bindVertices) ++ .bind(Two.Events.remove, unbindVertices); ++ ++ // Bind Initial Vertices ++ bindVertices(this._collection); ++ ++ } ++ ++ }); ++ ++ Object.defineProperty(object, 'clip', { ++ enumerable: true, ++ get: function() { ++ return this._clip; ++ }, ++ set: function(v) { ++ this._clip = v; ++ this._flagClip = true; ++ } ++ }); ++ ++ } ++ ++ }); ++ ++ _.extend(Path.prototype, Two.Shape.prototype, { ++ ++ // Flags ++ // http://en.wikipedia.org/wiki/Flag ++ ++ _flagVertices: true, ++ _flagLength: true, ++ ++ _flagFill: true, ++ _flagStroke: true, ++ _flagLinewidth: true, ++ _flagOpacity: true, ++ _flagVisible: true, ++ ++ _flagCap: true, ++ _flagJoin: true, ++ _flagMiter: true, ++ ++ _flagClip: false, ++ ++ // Underlying Properties ++ ++ _length: 0, ++ ++ _fill: '#fff', ++ _stroke: '#000', ++ _linewidth: 1.0, ++ _opacity: 1.0, ++ _visible: true, ++ ++ _cap: 'round', ++ _join: 'round', ++ _miter: 4, ++ ++ _closed: true, ++ _curved: false, ++ _automatic: true, ++ _beginning: 0, ++ _ending: 1.0, ++ ++ _clip: false, ++ ++ clone: function(parent) { ++ ++ parent = parent || this.parent; ++ ++ var points = _.map(this.vertices, function(v) { ++ return v.clone(); ++ }); ++ ++ var clone = new Path(points, this.closed, this.curved, !this.automatic); ++ ++ _.each(Two.Path.Properties, function(k) { ++ clone[k] = this[k]; ++ }, this); ++ ++ clone.translation.copy(this.translation); ++ clone.rotation = this.rotation; ++ clone.scale = this.scale; ++ ++ if (parent) { ++ parent.add(clone); ++ } ++ ++ return clone; ++ ++ }, ++ ++ toObject: function() { ++ ++ var result = { ++ vertices: _.map(this.vertices, function(v) { ++ return v.toObject(); ++ }) ++ }; ++ ++ _.each(Two.Shape.Properties, function(k) { ++ result[k] = this[k]; ++ }, this); ++ ++ result.translation = this.translation.toObject; ++ result.rotation = this.rotation; ++ result.scale = this.scale; ++ ++ return result; ++ ++ }, ++ ++ noFill: function() { ++ this.fill = 'transparent'; ++ return this; ++ }, ++ ++ noStroke: function() { ++ this.stroke = 'transparent'; ++ return this; ++ }, ++ ++ /** ++ * Orient the vertices of the shape to the upper lefthand ++ * corner of the path. ++ */ ++ corner: function() { ++ ++ var rect = this.getBoundingClientRect(true); ++ ++ rect.centroid = { ++ x: rect.left + rect.width / 2, ++ y: rect.top + rect.height / 2 ++ }; ++ ++ _.each(this.vertices, function(v) { ++ v.addSelf(rect.centroid); ++ }); ++ ++ return this; ++ ++ }, ++ ++ /** ++ * Orient the vertices of the shape to the center of the ++ * path. ++ */ ++ center: function() { ++ ++ var rect = this.getBoundingClientRect(true); ++ ++ rect.centroid = { ++ x: rect.left + rect.width / 2, ++ y: rect.top + rect.height / 2 ++ }; ++ ++ _.each(this.vertices, function(v) { ++ v.subSelf(rect.centroid); ++ }); ++ ++ // this.translation.addSelf(rect.centroid); ++ ++ return this; ++ ++ }, ++ ++ /** ++ * Remove self from the scene / parent. ++ */ ++ remove: function() { ++ ++ if (!this.parent) { ++ return this; ++ } ++ ++ this.parent.remove(this); ++ ++ return this; ++ ++ }, ++ ++ /** ++ * Return an object with top, left, right, bottom, width, and height ++ * parameters of the group. ++ */ ++ getBoundingClientRect: function(shallow) { ++ var matrix, border, l, x, y, i, v; ++ ++ var left = Infinity, right = -Infinity, ++ top = Infinity, bottom = -Infinity; ++ ++ // TODO: Update this to not __always__ update. Just when it needs to. ++ this._update(true); ++ ++ matrix = !!shallow ? this._matrix : getComputedMatrix(this); ++ ++ border = this.linewidth / 2; ++ l = this._vertices.length; ++ ++ if (l <= 0) { ++ v = matrix.multiply(0, 0, 1); ++ return { ++ top: v.y, ++ left: v.x, ++ right: v.x, ++ bottom: v.y, ++ width: 0, ++ height: 0 ++ }; ++ } ++ ++ for (i = 0; i < l; i++) { ++ v = this._vertices[i]; ++ ++ x = v.x; ++ y = v.y; ++ ++ v = matrix.multiply(x, y, 1); ++ top = min(v.y - border, top); ++ left = min(v.x - border, left); ++ right = max(v.x + border, right); ++ bottom = max(v.y + border, bottom); ++ } ++ ++ return { ++ top: top, ++ left: left, ++ right: right, ++ bottom: bottom, ++ width: right - left, ++ height: bottom - top ++ }; ++ ++ }, ++ ++ /** ++ * Given a float `t` from 0 to 1, return a point or assign a passed `obj`'s ++ * coordinates to that percentage on this Two.Path's curve. ++ */ ++ getPointAt: function(t, obj) { ++ var ia, ib; ++ var x, x1, x2, x3, x4, y, y1, y2, y3, y4, left, right; ++ var target = this.length * Math.min(Math.max(t, 0), 1); ++ var length = this.vertices.length; ++ var last = length - 1; ++ ++ var a = null; ++ var b = null; ++ ++ for (var i = 0, l = this._lengths.length, sum = 0; i < l; i++) { ++ ++ if (sum + this._lengths[i] >= target) { ++ ++ if (this._closed) { ++ ia = Two.Utils.mod(i, length); ++ ib = Two.Utils.mod(i - 1, length); ++ if (i === 0) { ++ ia = ib; ++ ib = i; ++ } ++ } else { ++ ia = i; ++ ib = Math.min(Math.max(i - 1, 0), last); ++ } ++ ++ a = this.vertices[ia]; ++ b = this.vertices[ib]; ++ target -= sum; ++ if (this._lengths[i] !== 0) { ++ t = target / this._lengths[i]; ++ } ++ ++ break; ++ ++ } ++ ++ sum += this._lengths[i]; ++ ++ } ++ ++ // console.log(sum, a.command, b.command); ++ ++ if (_.isNull(a) || _.isNull(b)) { ++ return null; ++ } ++ ++ right = b.controls && b.controls.right; ++ left = a.controls && a.controls.left; ++ ++ x1 = b.x; ++ y1 = b.y; ++ x2 = (right || b).x; ++ y2 = (right || b).y; ++ x3 = (left || a).x; ++ y3 = (left || a).y; ++ x4 = a.x; ++ y4 = a.y; ++ ++ if (right && b._relative) { ++ x2 += b.x; ++ y2 += b.y; ++ } ++ ++ if (left && a._relative) { ++ x3 += a.x; ++ y3 += a.y; ++ } ++ ++ x = Two.Utils.getPointOnCubicBezier(t, x1, x2, x3, x4); ++ y = Two.Utils.getPointOnCubicBezier(t, y1, y2, y3, y4); ++ ++ if (_.isObject(obj)) { ++ obj.x = x; ++ obj.y = y; ++ return obj; ++ } ++ ++ return new Two.Vector(x, y); ++ ++ }, ++ ++ /** ++ * Based on closed / curved and sorting of vertices plot where all points ++ * should be and where the respective handles should be too. ++ */ ++ plot: function() { ++ ++ if (this.curved) { ++ Two.Utils.getCurveFromPoints(this._vertices, this.closed); ++ return this; ++ } ++ ++ for (var i = 0; i < this._vertices.length; i++) { ++ this._vertices[i]._command = i === 0 ? Two.Commands.move : Two.Commands.line; ++ } ++ ++ return this; ++ ++ }, ++ ++ subdivide: function(limit) { ++ //TODO: DRYness (function below) ++ this._update(); ++ ++ var last = this.vertices.length - 1; ++ var b = this.vertices[last]; ++ var closed = this._closed || this.vertices[last]._command === Two.Commands.close; ++ var points = []; ++ _.each(this.vertices, function(a, i) { ++ ++ if (i <= 0 && !closed) { ++ b = a; ++ return; ++ } ++ ++ if (a.command === Two.Commands.move) { ++ points.push(new Two.Anchor(b.x, b.y)); ++ if (i > 0) { ++ points[points.length - 1].command = Two.Commands.line; ++ } ++ b = a; ++ return; ++ } ++ ++ var verts = getSubdivisions(a, b, limit); ++ points = points.concat(verts); ++ ++ // Assign commands to all the verts ++ _.each(verts, function(v, i) { ++ if (i <= 0 && b.command === Two.Commands.move) { ++ v.command = Two.Commands.move; ++ } else { ++ v.command = Two.Commands.line; ++ } ++ }); ++ ++ if (i >= last) { ++ ++ // TODO: Add check if the two vectors in question are the same values. ++ if (this._closed && this._automatic) { ++ ++ b = a; ++ ++ verts = getSubdivisions(a, b, limit); ++ points = points.concat(verts); ++ ++ // Assign commands to all the verts ++ _.each(verts, function(v, i) { ++ if (i <= 0 && b.command === Two.Commands.move) { ++ v.command = Two.Commands.move; ++ } else { ++ v.command = Two.Commands.line; ++ } ++ }); ++ ++ } else if (closed) { ++ points.push(new Two.Anchor(a.x, a.y)); ++ } ++ ++ points[points.length - 1].command = closed ? Two.Commands.close : Two.Commands.line; ++ ++ } ++ ++ b = a; ++ ++ }, this); ++ ++ this._automatic = false; ++ this._curved = false; ++ this.vertices = points; ++ ++ return this; ++ ++ }, ++ ++ _updateLength: function(limit) { ++ //TODO: DRYness (function above) ++ this._update(); ++ ++ var length = this.vertices.length; ++ var last = length - 1; ++ var b = this.vertices[last]; ++ var closed = this._closed || this.vertices[last]._command === Two.Commands.close; ++ var sum = 0; ++ ++ if (_.isUndefined(this._lengths)) { ++ this._lengths = []; ++ } ++ ++ _.each(this.vertices, function(a, i) { ++ ++ if ((i <= 0 && !closed) || a.command === Two.Commands.move) { ++ b = a; ++ this._lengths[i] = 0; ++ return; ++ } ++ ++ this._lengths[i] = getCurveLength(a, b, limit); ++ sum += this._lengths[i]; ++ ++ if (i >= last && closed) { ++ ++ b = this.vertices[(i + 1) % length]; ++ ++ this._lengths[i + 1] = getCurveLength(a, b, limit); ++ sum += this._lengths[i + 1]; ++ ++ } ++ ++ b = a; ++ ++ }, this); ++ ++ this._length = sum; ++ ++ return this; ++ ++ }, ++ ++ _update: function() { ++ ++ if (this._flagVertices) { ++ ++ var l = this.vertices.length; ++ var last = l - 1, v; ++ ++ // TODO: Should clamp this so that `ia` and `ib` ++ // cannot select non-verts. ++ var ia = round((this._beginning) * last); ++ var ib = round((this._ending) * last); ++ ++ this._vertices.length = 0; ++ ++ for (var i = ia; i < ib + 1; i++) { ++ v = this.vertices[i]; ++ this._vertices.push(v); ++ } ++ ++ if (this._automatic) { ++ this.plot(); ++ } ++ ++ } ++ ++ Two.Shape.prototype._update.apply(this, arguments); ++ ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagVertices = this._flagFill = this._flagStroke = ++ this._flagLinewidth = this._flagOpacity = this._flagVisible = ++ this._flagCap = this._flagJoin = this._flagMiter = ++ this._flagClip = false; ++ ++ Two.Shape.prototype.flagReset.call(this); ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ Path.MakeObservable(Path.prototype); ++ ++ /** ++ * Utility functions ++ */ ++ ++ function getCurveLength(a, b, limit) { ++ // TODO: DRYness ++ var x1, x2, x3, x4, y1, y2, y3, y4; ++ ++ var right = b.controls && b.controls.right; ++ var left = a.controls && a.controls.left; ++ ++ x1 = b.x; ++ y1 = b.y; ++ x2 = (right || b).x; ++ y2 = (right || b).y; ++ x3 = (left || a).x; ++ y3 = (left || a).y; ++ x4 = a.x; ++ y4 = a.y; ++ ++ if (right && b._relative) { ++ x2 += b.x; ++ y2 += b.y; ++ } ++ ++ if (left && a._relative) { ++ x3 += a.x; ++ y3 += a.y; ++ } ++ ++ return Two.Utils.getCurveLength(x1, y1, x2, y2, x3, y3, x4, y4, limit); ++ ++ } ++ ++ function getSubdivisions(a, b, limit) { ++ // TODO: DRYness ++ var x1, x2, x3, x4, y1, y2, y3, y4; ++ ++ var right = b.controls && b.controls.right; ++ var left = a.controls && a.controls.left; ++ ++ x1 = b.x; ++ y1 = b.y; ++ x2 = (right || b).x; ++ y2 = (right || b).y; ++ x3 = (left || a).x; ++ y3 = (left || a).y; ++ x4 = a.x; ++ y4 = a.y; ++ ++ if (right && b._relative) { ++ x2 += b.x; ++ y2 += b.y; ++ } ++ ++ if (left && a._relative) { ++ x3 += a.x; ++ y3 += a.y; ++ } ++ ++ return Two.Utils.subdivide(x1, y1, x2, y2, x3, y3, x4, y4, limit); ++ ++ } ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var Path = Two.Path; ++ var _ = Two.Utils; ++ ++ var Line = Two.Line = function(x1, y1, x2, y2) { ++ ++ var width = x2 - x1; ++ var height = y2 - y1; ++ ++ var w2 = width / 2; ++ var h2 = height / 2; ++ ++ Path.call(this, [ ++ new Two.Anchor(- w2, - h2), ++ new Two.Anchor(w2, h2) ++ ]); ++ ++ this.translation.set(x1 + w2, y1 + h2); ++ ++ }; ++ ++ _.extend(Line.prototype, Path.prototype); ++ ++ Path.MakeObservable(Line.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var Path = Two.Path; ++ var _ = Two.Utils; ++ ++ var Rectangle = Two.Rectangle = function(x, y, width, height) { ++ ++ Path.call(this, [ ++ new Two.Anchor(), ++ new Two.Anchor(), ++ new Two.Anchor(), ++ new Two.Anchor() ++ ], true); ++ ++ this.width = width; ++ this.height = height; ++ this._update(); ++ ++ this.translation.set(x, y); ++ ++ }; ++ ++ _.extend(Rectangle, { ++ ++ Properties: ['width', 'height'], ++ ++ MakeObservable: function(obj) { ++ Path.MakeObservable(obj); ++ _.each(Rectangle.Properties, Two.Utils.defineProperty, obj); ++ } ++ ++ }); ++ ++ _.extend(Rectangle.prototype, Path.prototype, { ++ ++ _width: 0, ++ _height: 0, ++ ++ _flagWidth: 0, ++ _flagHeight: 0, ++ ++ _update: function() { ++ ++ if (this._flagWidth || this._flagHeight) { ++ ++ var xr = this._width / 2; ++ var yr = this._height / 2; ++ ++ this.vertices[0].set(-xr, -yr); ++ this.vertices[1].set(xr, -yr); ++ this.vertices[2].set(xr, yr); ++ this.vertices[3].set(-xr, yr); ++ ++ } ++ ++ Path.prototype._update.call(this); ++ ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagWidth = this._flagHeight = false; ++ Path.prototype.flagReset.call(this); ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ Rectangle.MakeObservable(Rectangle.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var Path = Two.Path, TWO_PI = Math.PI * 2, cos = Math.cos, sin = Math.sin; ++ var _ = Two.Utils; ++ ++ var Ellipse = Two.Ellipse = function(ox, oy, rx, ry) { ++ ++ if (!_.isNumber(ry)) { ++ ry = rx; ++ } ++ ++ var amount = Two.Resolution; ++ ++ var points = _.map(_.range(amount), function(i) { ++ return new Two.Anchor(); ++ }, this); ++ ++ Path.call(this, points, true, true); ++ ++ this.width = rx * 2; ++ this.height = ry * 2; ++ ++ this._update(); ++ this.translation.set(ox, oy); ++ ++ }; ++ ++ _.extend(Ellipse, { ++ ++ Properties: ['width', 'height'], ++ ++ MakeObservable: function(obj) { ++ ++ Path.MakeObservable(obj); ++ _.each(Ellipse.Properties, Two.Utils.defineProperty, obj); ++ ++ } ++ ++ }); ++ ++ _.extend(Ellipse.prototype, Path.prototype, { ++ ++ _width: 0, ++ _height: 0, ++ ++ _flagWidth: false, ++ _flagHeight: false, ++ ++ _update: function() { ++ ++ if (this._flagWidth || this._flagHeight) { ++ for (var i = 0, l = this.vertices.length; i < l; i++) { ++ var pct = i / l; ++ var theta = pct * TWO_PI; ++ var x = this._width * cos(theta) / 2; ++ var y = this._height * sin(theta) / 2; ++ this.vertices[i].set(x, y); ++ } ++ } ++ ++ Path.prototype._update.call(this); ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagWidth = this._flagHeight = false; ++ ++ Path.prototype.flagReset.call(this); ++ return this; ++ ++ } ++ ++ }); ++ ++ Ellipse.MakeObservable(Ellipse.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var Path = Two.Path, TWO_PI = Math.PI * 2, cos = Math.cos, sin = Math.sin; ++ var _ = Two.Utils; ++ ++ var Circle = Two.Circle = function(ox, oy, r) { ++ ++ var amount = Two.Resolution; ++ ++ var points = _.map(_.range(amount), function(i) { ++ return new Two.Anchor(); ++ }, this); ++ ++ Path.call(this, points, true, true); ++ ++ this.radius = r; ++ ++ this._update(); ++ this.translation.set(ox, oy); ++ ++ }; ++ ++ _.extend(Circle, { ++ ++ Properties: ['radius'], ++ ++ MakeObservable: function(obj) { ++ ++ Path.MakeObservable(obj); ++ _.each(Circle.Properties, Two.Utils.defineProperty, obj); ++ ++ } ++ ++ }); ++ ++ _.extend(Circle.prototype, Path.prototype, { ++ ++ _radius: 0, ++ _flagRadius: false, ++ ++ _update: function() { ++ ++ if (this._flagRadius) { ++ for (var i = 0, l = this.vertices.length; i < l; i++) { ++ var pct = i / l; ++ var theta = pct * TWO_PI; ++ var x = this._radius * cos(theta); ++ var y = this._radius * sin(theta); ++ this.vertices[i].set(x, y); ++ } ++ } ++ ++ Path.prototype._update.call(this); ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagRadius = false; ++ ++ Path.prototype.flagReset.call(this); ++ return this; ++ ++ } ++ ++ }); ++ ++ Circle.MakeObservable(Circle.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var Path = Two.Path, TWO_PI = Math.PI * 2, cos = Math.cos, sin = Math.sin; ++ var _ = Two.Utils; ++ ++ var Polygon = Two.Polygon = function(ox, oy, r, sides) { ++ ++ sides = Math.max(sides || 0, 3); ++ ++ var points = _.map(_.range(sides), function(i) { ++ return new Two.Anchor(); ++ }); ++ ++ Path.call(this, points, true); ++ ++ this.width = r * 2; ++ this.height = r * 2; ++ this.sides = sides; ++ ++ this._update(); ++ this.translation.set(ox, oy); ++ ++ }; ++ ++ _.extend(Polygon, { ++ ++ Properties: ['width', 'height', 'sides'], ++ ++ MakeObservable: function(obj) { ++ ++ Path.MakeObservable(obj); ++ _.each(Polygon.Properties, Two.Utils.defineProperty, obj); ++ ++ } ++ ++ }); ++ ++ _.extend(Polygon.prototype, Path.prototype, { ++ ++ _width: 0, ++ _height: 0, ++ _sides: 0, ++ ++ _flagWidth: false, ++ _flagHeight: false, ++ _flagSides: false, ++ ++ _update: function() { ++ ++ if (this._flagWidth || this._flagHeight || this._flagSides) { ++ ++ var sides = this._sides; ++ var amount = this.vertices.length; ++ ++ if (amount > sides) { ++ this.vertices.splice(sides - 1, amount - sides); ++ } ++ ++ for (var i = 0; i < sides; i++) { ++ ++ var pct = (i + 0.5) / sides; ++ var theta = TWO_PI * pct + Math.PI / 2; ++ var x = this._width * cos(theta); ++ var y = this._height * sin(theta); ++ ++ if (i >= amount) { ++ this.vertices.push(new Two.Anchor(x, y)); ++ } else { ++ this.vertices[i].set(x, y); ++ } ++ ++ } ++ ++ } ++ ++ Path.prototype._update.call(this); ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagWidth = this._flagHeight = this._flagSides = false; ++ Path.prototype.flagReset.call(this); ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ Polygon.MakeObservable(Polygon.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var Path = Two.Path, PI = Math.PI, TWO_PI = Math.PI * 2, HALF_PI = Math.PI / 2, ++ cos = Math.cos, sin = Math.sin, abs = Math.abs, _ = Two.Utils; ++ ++ var ArcSegment = Two.ArcSegment = function(ox, oy, ir, or, sa, ea, res) { ++ ++ var points = _.map(_.range(res || (Two.Resolution * 3)), function() { ++ return new Two.Anchor(); ++ }); ++ ++ Path.call(this, points, false, false, true); ++ ++ this.innerRadius = ir; ++ this.outerRadius = or; ++ ++ this.startAngle = sa; ++ this.endAngle = ea; ++ ++ this._update(); ++ this.translation.set(ox, oy); ++ ++ } ++ ++ _.extend(ArcSegment, { ++ ++ Properties: ['startAngle', 'endAngle', 'innerRadius', 'outerRadius'], ++ ++ MakeObservable: function(obj) { ++ ++ Path.MakeObservable(obj); ++ _.each(ArcSegment.Properties, Two.Utils.defineProperty, obj); ++ ++ } ++ ++ }); ++ ++ _.extend(ArcSegment.prototype, Path.prototype, { ++ ++ _flagStartAngle: false, ++ _flagEndAngle: false, ++ _flagInnerRadius: false, ++ _flagOuterRadius: false, ++ ++ _startAngle: 0, ++ _endAngle: TWO_PI, ++ _innerRadius: 0, ++ _outerRadius: 0, ++ ++ _update: function() { ++ ++ if (this._flagStartAngle || this._flagEndAngle || this._flagInnerRadius ++ || this._flagOuterRadius) { ++ ++ var sa = this._startAngle; ++ var ea = this._endAngle; ++ ++ var ir = this._innerRadius; ++ var or = this._outerRadius; ++ ++ var connected = mod(sa, TWO_PI) === mod(ea, TWO_PI); ++ var punctured = ir > 0; ++ ++ var vertices = this.vertices; ++ var length = (punctured ? vertices.length / 2 : vertices.length); ++ var command, id = 0; ++ ++ if (connected) { ++ length--; ++ } else if (!punctured) { ++ length -= 2; ++ } ++ ++ /** ++ * Outer Circle ++ */ ++ for (var i = 0, last = length - 1; i < length; i++) { ++ ++ var pct = i / last; ++ var v = vertices[id]; ++ var theta = pct * (ea - sa) + sa; ++ var step = (ea - sa) / length; ++ ++ var x = or * Math.cos(theta); ++ var y = or * Math.sin(theta); ++ ++ switch (i) { ++ case 0: ++ command = Two.Commands.move; ++ break; ++ default: ++ command = Two.Commands.curve; ++ } ++ ++ v.command = command; ++ v.x = x; ++ v.y = y; ++ v.controls.left.clear(); ++ v.controls.right.clear(); ++ ++ if (v.command === Two.Commands.curve) { ++ var amp = or * step / Math.PI; ++ v.controls.left.x = amp * Math.cos(theta - HALF_PI); ++ v.controls.left.y = amp * Math.sin(theta - HALF_PI); ++ v.controls.right.x = amp * Math.cos(theta + HALF_PI); ++ v.controls.right.y = amp * Math.sin(theta + HALF_PI); ++ if (i === 1) { ++ v.controls.left.multiplyScalar(2); ++ } ++ if (i === last) { ++ v.controls.right.multiplyScalar(2); ++ } ++ } ++ ++ id++; ++ ++ } ++ ++ if (punctured) { ++ ++ if (connected) { ++ vertices[id].command = Two.Commands.close; ++ id++; ++ } else { ++ length--; ++ last = length - 1; ++ } ++ ++ /** ++ * Inner Circle ++ */ ++ for (i = 0; i < length; i++) { ++ ++ pct = i / last; ++ v = vertices[id]; ++ theta = (1 - pct) * (ea - sa) + sa; ++ step = (ea - sa) / length; ++ ++ x = ir * Math.cos(theta); ++ y = ir * Math.sin(theta); ++ command = Two.Commands.curve; ++ if (i <= 0) { ++ command = connected ? Two.Commands.move : Two.Commands.line; ++ } ++ ++ v.command = command; ++ v.x = x; ++ v.y = y; ++ v.controls.left.clear(); ++ v.controls.right.clear(); ++ ++ if (v.command === Two.Commands.curve) { ++ amp = ir * step / Math.PI; ++ v.controls.left.x = amp * Math.cos(theta + HALF_PI); ++ v.controls.left.y = amp * Math.sin(theta + HALF_PI); ++ v.controls.right.x = amp * Math.cos(theta - HALF_PI); ++ v.controls.right.y = amp * Math.sin(theta - HALF_PI); ++ if (i === 1) { ++ v.controls.left.multiplyScalar(2); ++ } ++ if (i === last) { ++ v.controls.right.multiplyScalar(2); ++ } ++ } ++ ++ id++; ++ ++ } ++ ++ } else if (!connected) { ++ ++ vertices[id].command = Two.Commands.line; ++ vertices[id].x = 0; ++ vertices[id].y = 0; ++ id++; ++ ++ } ++ ++ /** ++ * Final Point ++ */ ++ vertices[id].command = Two.Commands.close; ++ ++ } ++ ++ Path.prototype._update.call(this); ++ ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ Path.prototype.flagReset.call(this); ++ ++ this._flagStartAngle = this._flagEndAngle ++ = this._flagInnerRadius = this._flagOuterRadius = false; ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ ArcSegment.MakeObservable(ArcSegment.prototype); ++ ++ function mod(v, l) { ++ while (v < 0) { ++ v += l; ++ } ++ return v % l; ++ } ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var Path = Two.Path, TWO_PI = Math.PI * 2, cos = Math.cos, sin = Math.sin; ++ var _ = Two.Utils; ++ ++ var Star = Two.Star = function(ox, oy, or, ir, sides) { ++ ++ if (!_.isNumber(ir)) { ++ ir = or / 2; ++ } ++ ++ if (!_.isNumber(sides) || sides <= 0) { ++ sides = 5; ++ } ++ ++ var length = sides * 2; ++ ++ var points = _.map(_.range(length), function(i) { ++ return new Two.Anchor(); ++ }); ++ ++ Path.call(this, points, true); ++ ++ this.innerRadius = ir; ++ this.outerRadius = or; ++ this.sides = sides; ++ ++ this._update(); ++ this.translation.set(ox, oy); ++ ++ }; ++ ++ _.extend(Star, { ++ ++ Properties: ['innerRadius', 'outerRadius', 'sides'], ++ ++ MakeObservable: function(obj) { ++ ++ Path.MakeObservable(obj); ++ _.each(Star.Properties, Two.Utils.defineProperty, obj); ++ ++ } ++ ++ }); ++ ++ _.extend(Star.prototype, Path.prototype, { ++ ++ _innerRadius: 0, ++ _outerRadius: 0, ++ _sides: 0, ++ ++ _flagInnerRadius: false, ++ _flagOuterRadius: false, ++ _flagSides: false, ++ ++ _update: function() { ++ ++ if (this._flagInnerRadius || this._flagOuterRadius || this._flagSides) { ++ ++ var sides = this._sides * 2; ++ var amount = this.vertices.length; ++ ++ if (amount > sides) { ++ this.vertices.splice(sides - 1, amount - sides); ++ } ++ ++ for (var i = 0; i < sides; i++) { ++ ++ var pct = (i + 0.5) / sides; ++ var theta = TWO_PI * pct; ++ var r = (i % 2 ? this._innerRadius : this._outerRadius); ++ var x = r * cos(theta); ++ var y = r * sin(theta); ++ ++ if (i >= amount) { ++ this.vertices.push(new Two.Anchor(x, y)); ++ } else { ++ this.vertices[i].set(x, y); ++ } ++ ++ } ++ ++ } ++ ++ Path.prototype._update.call(this); ++ ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagInnerRadius = this._flagOuterRadius = this._flagSides = false; ++ Path.prototype.flagReset.call(this); ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ Star.MakeObservable(Star.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var Path = Two.Path; ++ var _ = Two.Utils; ++ ++ var RoundedRectangle = Two.RoundedRectangle = function(ox, oy, width, height, radius) { ++ ++ if (!_.isNumber(radius)) { ++ radius = Math.floor(Math.min(width, height) / 12); ++ } ++ ++ var amount = 10; ++ ++ var points = _.map(_.range(amount), function(i) { ++ return new Two.Anchor(0, 0, 0, 0, 0, 0, ++ i === 0 ? Two.Commands.move : Two.Commands.curve); ++ }); ++ ++ points[points.length - 1].command = Two.Commands.close; ++ ++ Path.call(this, points, false, false, true); ++ ++ this.width = width; ++ this.height = height; ++ this.radius = radius; ++ ++ this._update(); ++ this.translation.set(ox, oy); ++ ++ }; ++ ++ _.extend(RoundedRectangle, { ++ ++ Properties: ['width', 'height', 'radius'], ++ ++ MakeObservable: function(obj) { ++ ++ Path.MakeObservable(obj); ++ _.each(RoundedRectangle.Properties, Two.Utils.defineProperty, obj); ++ ++ } ++ ++ }); ++ ++ _.extend(RoundedRectangle.prototype, Path.prototype, { ++ ++ _width: 0, ++ _height: 0, ++ _radius: 0, ++ ++ _flagWidth: false, ++ _flagHeight: false, ++ _flagRadius: false, ++ ++ _update: function() { ++ ++ if (this._flagWidth || this._flagHeight || this._flagRadius) { ++ ++ var width = this._width; ++ var height = this._height; ++ var radius = Math.min(Math.max(this._radius, 0), ++ Math.min(width, height)); ++ ++ var v; ++ var w = width / 2; ++ var h = height / 2; ++ ++ v = this.vertices[0]; ++ v.x = - (w - radius); ++ v.y = - h; ++ ++ // Upper Right Corner ++ ++ v = this.vertices[1]; ++ v.x = (w - radius); ++ v.y = - h; ++ v.controls.left.clear(); ++ v.controls.right.x = radius; ++ v.controls.right.y = 0; ++ ++ v = this.vertices[2]; ++ v.x = w; ++ v.y = - (h - radius); ++ v.controls.right.clear(); ++ v.controls.left.clear(); ++ ++ // Bottom Right Corner ++ ++ v = this.vertices[3]; ++ v.x = w; ++ v.y = (h - radius); ++ v.controls.left.clear(); ++ v.controls.right.x = 0; ++ v.controls.right.y = radius; ++ ++ v = this.vertices[4]; ++ v.x = (w - radius); ++ v.y = h; ++ v.controls.right.clear(); ++ v.controls.left.clear(); ++ ++ // Bottom Left Corner ++ ++ v = this.vertices[5]; ++ v.x = - (w - radius); ++ v.y = h; ++ v.controls.left.clear(); ++ v.controls.right.x = - radius; ++ v.controls.right.y = 0; ++ ++ v = this.vertices[6]; ++ v.x = - w; ++ v.y = (h - radius); ++ v.controls.left.clear(); ++ v.controls.right.clear(); ++ ++ // Upper Left Corner ++ ++ v = this.vertices[7]; ++ v.x = - w; ++ v.y = - (h - radius); ++ v.controls.left.clear(); ++ v.controls.right.x = 0; ++ v.controls.right.y = - radius; ++ ++ v = this.vertices[8]; ++ v.x = - (w - radius); ++ v.y = - h; ++ v.controls.left.clear(); ++ v.controls.right.clear(); ++ ++ v = this.vertices[9]; ++ v.copy(this.vertices[8]); ++ ++ } ++ ++ Path.prototype._update.call(this); ++ ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagWidth = this._flagHeight = this._flagRadius = false; ++ Path.prototype.flagReset.call(this); ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ RoundedRectangle.MakeObservable(RoundedRectangle.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var root = Two.root; ++ var getComputedMatrix = Two.Utils.getComputedMatrix; ++ var _ = Two.Utils; ++ ++ var canvas = (root.document ? root.document.createElement('canvas') : { getContext: _.identity }); ++ var ctx = canvas.getContext('2d'); ++ ++ var Text = Two.Text = function(message, x, y, styles) { ++ ++ Two.Shape.call(this); ++ ++ this._renderer.type = 'text'; ++ this._renderer.flagFill = _.bind(Text.FlagFill, this); ++ this._renderer.flagStroke = _.bind(Text.FlagStroke, this); ++ ++ this.value = message; ++ ++ if (_.isNumber(x)) { ++ this.translation.x = x; ++ } ++ if (_.isNumber(y)) { ++ this.translation.y = y; ++ } ++ ++ if (!_.isObject(styles)) { ++ return this; ++ } ++ ++ _.each(Two.Text.Properties, function(property) { ++ ++ if (property in styles) { ++ this[property] = styles[property]; ++ } ++ ++ }, this); ++ ++ }; ++ ++ _.extend(Two.Text, { ++ ++ Properties: [ ++ 'value', 'family', 'size', 'leading', 'alignment', 'linewidth', 'style', ++ 'weight', 'decoration', 'baseline', 'opacity', 'visible', 'fill', 'stroke' ++ ], ++ ++ FlagFill: function() { ++ this._flagFill = true; ++ }, ++ ++ FlagStroke: function() { ++ this._flagStroke = true; ++ }, ++ ++ MakeObservable: function(object) { ++ ++ Two.Shape.MakeObservable(object); ++ ++ _.each(Two.Text.Properties.slice(0, 12), Two.Utils.defineProperty, object); ++ ++ Object.defineProperty(object, 'fill', { ++ enumerable: true, ++ get: function() { ++ return this._fill; ++ }, ++ set: function(f) { ++ ++ if (this._fill instanceof Two.Gradient ++ || this._fill instanceof Two.LinearGradient ++ || this._fill instanceof Two.RadialGradient ++ || this._fill instanceof Two.Texture) { ++ this._fill.unbind(Two.Events.change, this._renderer.flagFill); ++ } ++ ++ this._fill = f; ++ this._flagFill = true; ++ ++ if (this._fill instanceof Two.Gradient ++ || this._fill instanceof Two.LinearGradient ++ || this._fill instanceof Two.RadialGradient ++ || this._fill instanceof Two.Texture) { ++ this._fill.bind(Two.Events.change, this._renderer.flagFill); ++ } ++ ++ } ++ }); ++ ++ Object.defineProperty(object, 'stroke', { ++ enumerable: true, ++ get: function() { ++ return this._stroke; ++ }, ++ set: function(f) { ++ ++ if (this._stroke instanceof Two.Gradient ++ || this._stroke instanceof Two.LinearGradient ++ || this._stroke instanceof Two.RadialGradient ++ || this._stroke instanceof Two.Texture) { ++ this._stroke.unbind(Two.Events.change, this._renderer.flagStroke); ++ } ++ ++ this._stroke = f; ++ this._flagStroke = true; ++ ++ if (this._stroke instanceof Two.Gradient ++ || this._stroke instanceof Two.LinearGradient ++ || this._stroke instanceof Two.RadialGradient ++ || this._stroke instanceof Two.Texture) { ++ this._stroke.bind(Two.Events.change, this._renderer.flagStroke); ++ } ++ ++ } ++ }); ++ ++ Object.defineProperty(object, 'clip', { ++ enumerable: true, ++ get: function() { ++ return this._clip; ++ }, ++ set: function(v) { ++ this._clip = v; ++ this._flagClip = true; ++ } ++ }); ++ ++ } ++ ++ }); ++ ++ _.extend(Two.Text.prototype, Two.Shape.prototype, { ++ ++ // Flags ++ // http://en.wikipedia.org/wiki/Flag ++ ++ _flagValue: true, ++ _flagFamily: true, ++ _flagSize: true, ++ _flagLeading: true, ++ _flagAlignment: true, ++ _flagBaseline: true, ++ _flagStyle: true, ++ _flagWeight: true, ++ _flagDecoration: true, ++ ++ _flagFill: true, ++ _flagStroke: true, ++ _flagLinewidth: true, ++ _flagOpacity: true, ++ _flagVisible: true, ++ ++ _flagClip: false, ++ ++ // Underlying Properties ++ ++ _value: '', ++ _family: 'sans-serif', ++ _size: 13, ++ _leading: 17, ++ _alignment: 'center', ++ _baseline: 'middle', ++ _style: 'normal', ++ _weight: 500, ++ _decoration: 'none', ++ ++ _fill: '#000', ++ _stroke: 'transparent', ++ _linewidth: 1, ++ _opacity: 1, ++ _visible: true, ++ ++ _clip: false, ++ ++ remove: function() { ++ ++ if (!this.parent) { ++ return this; ++ } ++ ++ this.parent.remove(this); ++ ++ return this; ++ ++ }, ++ ++ clone: function(parent) { ++ ++ var parent = parent || this.parent; ++ ++ var clone = new Two.Text(this.value); ++ clone.translation.copy(this.translation); ++ clone.rotation = this.rotation; ++ clone.scale = this.scale; ++ ++ _.each(Two.Text.Properties, function(property) { ++ clone[property] = this[property]; ++ }, this); ++ ++ if (parent) { ++ parent.add(clone); ++ } ++ ++ return clone; ++ ++ }, ++ ++ toObject: function() { ++ ++ var result = { ++ translation: this.translation.toObject(), ++ rotation: this.rotation, ++ scale: this.scale ++ }; ++ ++ _.each(Two.Text.Properties, function(property) { ++ result[property] = this[property]; ++ }, this); ++ ++ return result; ++ ++ }, ++ ++ noStroke: function() { ++ this.stroke = 'transparent'; ++ return this; ++ }, ++ ++ noFill: function() { ++ this.fill = 'transparent'; ++ return this; ++ }, ++ ++ /** ++ * A shim to not break `getBoundingClientRect` calls. TODO: Implement a ++ * way to calculate proper bounding boxes of `Two.Text`. ++ */ ++ getBoundingClientRect: function(shallow) { ++ ++ var matrix, border, l, x, y, i, v; ++ ++ var left = Infinity, right = -Infinity, ++ top = Infinity, bottom = -Infinity; ++ ++ // TODO: Update this to not __always__ update. Just when it needs to. ++ this._update(true); ++ ++ matrix = !!shallow ? this._matrix : getComputedMatrix(this); ++ ++ v = matrix.multiply(0, 0, 1); ++ ++ return { ++ top: v.x, ++ left: v.y, ++ right: v.x, ++ bottom: v.y, ++ width: 0, ++ height: 0 ++ }; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagValue = this._flagFamily = this._flagSize = ++ this._flagLeading = this._flagAlignment = this._flagFill = ++ this._flagStroke = this._flagLinewidth = this._flagOpaicty = ++ this._flagVisible = this._flagClip = this._flagDecoration = ++ this._flagBaseline = false; ++ ++ Two.Shape.prototype.flagReset.call(this); ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ Two.Text.MakeObservable(Two.Text.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var _ = Two.Utils; ++ ++ var Stop = Two.Stop = function(offset, color, opacity) { ++ ++ this._renderer = {}; ++ this._renderer.type = 'stop'; ++ ++ this.offset = _.isNumber(offset) ? offset ++ : Stop.Index <= 0 ? 0 : 1; ++ ++ this.opacity = _.isNumber(opacity) ? opacity : 1; ++ ++ this.color = _.isString(color) ? color ++ : Stop.Index <= 0 ? '#fff' : '#000'; ++ ++ Stop.Index = (Stop.Index + 1) % 2; ++ ++ }; ++ ++ _.extend(Stop, { ++ ++ Index: 0, ++ ++ Properties: [ ++ 'offset', ++ 'opacity', ++ 'color' ++ ], ++ ++ MakeObservable: function(object) { ++ ++ _.each(Stop.Properties, function(property) { ++ ++ var object = this; ++ var secret = '_' + property; ++ var flag = '_flag' + property.charAt(0).toUpperCase() + property.slice(1); ++ ++ Object.defineProperty(object, property, { ++ enumerable: true, ++ get: function() { ++ return this[secret]; ++ }, ++ set: function(v) { ++ this[secret] = v; ++ this[flag] = true; ++ if (this.parent) { ++ this.parent._flagStops = true; ++ } ++ } ++ }); ++ ++ }, object); ++ ++ } ++ ++ }); ++ ++ _.extend(Stop.prototype, Two.Utils.Events, { ++ ++ clone: function() { ++ ++ var clone = new Stop(); ++ ++ _.each(Stop.Properties, function(property) { ++ clone[property] = this[property]; ++ }, this); ++ ++ return clone; ++ ++ }, ++ ++ toObject: function() { ++ ++ var result = {}; ++ ++ _.each(Stop.Properties, function(k) { ++ result[k] = this[k]; ++ }, this); ++ ++ return result; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagOffset = this._flagColor = this._flagOpacity = false; ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ Stop.MakeObservable(Stop.prototype); ++ ++ var Gradient = Two.Gradient = function(stops) { ++ ++ this._renderer = {}; ++ this._renderer.type = 'gradient'; ++ ++ this.id = Two.Identifier + Two.uniqueId(); ++ this.classList = []; ++ ++ this._renderer.flagStops = _.bind(Gradient.FlagStops, this); ++ this._renderer.bindStops = _.bind(Gradient.BindStops, this); ++ this._renderer.unbindStops = _.bind(Gradient.UnbindStops, this); ++ ++ this.spread = 'pad'; ++ ++ this.stops = stops; ++ ++ }; ++ ++ _.extend(Gradient, { ++ ++ Stop: Stop, ++ ++ Properties: [ ++ 'spread' ++ ], ++ ++ MakeObservable: function(object) { ++ ++ _.each(Gradient.Properties, Two.Utils.defineProperty, object); ++ ++ Object.defineProperty(object, 'stops', { ++ ++ enumerable: true, ++ ++ get: function() { ++ return this._stops; ++ }, ++ ++ set: function(stops) { ++ ++ var updateStops = this._renderer.flagStops; ++ var bindStops = this._renderer.bindStops; ++ var unbindStops = this._renderer.unbindStops; ++ ++ // Remove previous listeners ++ if (this._stops) { ++ this._stops ++ .unbind(Two.Events.insert, bindStops) ++ .unbind(Two.Events.remove, unbindStops); ++ } ++ ++ // Create new Collection with copy of Stops ++ this._stops = new Two.Utils.Collection((stops || []).slice(0)); ++ ++ // Listen for Collection changes and bind / unbind ++ this._stops ++ .bind(Two.Events.insert, bindStops) ++ .bind(Two.Events.remove, unbindStops); ++ ++ // Bind Initial Stops ++ bindStops(this._stops); ++ ++ } ++ ++ }); ++ ++ }, ++ ++ FlagStops: function() { ++ this._flagStops = true; ++ }, ++ ++ BindStops: function(items) { ++ ++ // This function is called a lot ++ // when importing a large SVG ++ var i = items.length; ++ while(i--) { ++ items[i].bind(Two.Events.change, this._renderer.flagStops); ++ items[i].parent = this; ++ } ++ ++ this._renderer.flagStops(); ++ ++ }, ++ ++ UnbindStops: function(items) { ++ ++ var i = items.length; ++ while(i--) { ++ items[i].unbind(Two.Events.change, this._renderer.flagStops); ++ delete items[i].parent; ++ } ++ ++ this._renderer.flagStops(); ++ ++ } ++ ++ }); ++ ++ _.extend(Gradient.prototype, Two.Utils.Events, { ++ ++ _flagStops: false, ++ _flagSpread: false, ++ ++ clone: function(parent) { ++ ++ parent = parent || this.parent; ++ ++ var stops = _.map(this.stops, function(s) { ++ return s.clone(); ++ }); ++ ++ var clone = new Gradient(stops); ++ ++ _.each(Two.Gradient.Properties, function(k) { ++ clone[k] = this[k]; ++ }, this); ++ ++ if (parent) { ++ parent.add(clone); ++ } ++ ++ return clone; ++ ++ }, ++ ++ toObject: function() { ++ ++ var result = { ++ stops: _.map(this.stops, function(s) { ++ return s.toObject(); ++ }) ++ }; ++ ++ _.each(Gradient.Properties, function(k) { ++ result[k] = this[k]; ++ }, this); ++ ++ return result; ++ ++ }, ++ ++ _update: function() { ++ ++ if (this._flagSpread || this._flagStops) { ++ this.trigger(Two.Events.change); ++ } ++ ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagSpread = this._flagStops = false; ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ Gradient.MakeObservable(Gradient.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var _ = Two.Utils; ++ ++ var LinearGradient = Two.LinearGradient = function(x1, y1, x2, y2, stops) { ++ ++ Two.Gradient.call(this, stops); ++ ++ this._renderer.type = 'linear-gradient'; ++ ++ var flagEndPoints = _.bind(LinearGradient.FlagEndPoints, this); ++ this.left = new Two.Vector().bind(Two.Events.change, flagEndPoints); ++ this.right = new Two.Vector().bind(Two.Events.change, flagEndPoints); ++ ++ if (_.isNumber(x1)) { ++ this.left.x = x1; ++ } ++ if (_.isNumber(y1)) { ++ this.left.y = y1; ++ } ++ if (_.isNumber(x2)) { ++ this.right.x = x2; ++ } ++ if (_.isNumber(y2)) { ++ this.right.y = y2; ++ } ++ ++ }; ++ ++ _.extend(LinearGradient, { ++ ++ Stop: Two.Gradient.Stop, ++ ++ MakeObservable: function(object) { ++ Two.Gradient.MakeObservable(object); ++ }, ++ ++ FlagEndPoints: function() { ++ this._flagEndPoints = true; ++ } ++ ++ }); ++ ++ _.extend(LinearGradient.prototype, Two.Gradient.prototype, { ++ ++ _flagEndPoints: false, ++ ++ clone: function(parent) { ++ ++ parent = parent || this.parent; ++ ++ var stops = _.map(this.stops, function(stop) { ++ return stop.clone(); ++ }); ++ ++ var clone = new LinearGradient(this.left._x, this.left._y, ++ this.right._x, this.right._y, stops); ++ ++ _.each(Two.Gradient.Properties, function(k) { ++ clone[k] = this[k]; ++ }, this); ++ ++ if (parent) { ++ parent.add(clone); ++ } ++ ++ return clone; ++ ++ }, ++ ++ toObject: function() { ++ ++ var result = Two.Gradient.prototype.toObject.call(this); ++ ++ result.left = this.left.toObject(); ++ result.right = this.right.toObject(); ++ ++ return result; ++ ++ }, ++ ++ _update: function() { ++ ++ if (this._flagEndPoints || this._flagSpread || this._flagStops) { ++ this.trigger(Two.Events.change); ++ } ++ ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagEndPoints = false; ++ ++ Two.Gradient.prototype.flagReset.call(this); ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ LinearGradient.MakeObservable(LinearGradient.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var _ = Two.Utils; ++ ++ var RadialGradient = Two.RadialGradient = function(cx, cy, r, stops, fx, fy) { ++ ++ Two.Gradient.call(this, stops); ++ ++ this._renderer.type = 'radial-gradient'; ++ ++ this.center = new Two.Vector() ++ .bind(Two.Events.change, _.bind(function() { ++ this._flagCenter = true; ++ }, this)); ++ ++ this.radius = _.isNumber(r) ? r : 20; ++ ++ this.focal = new Two.Vector() ++ .bind(Two.Events.change, _.bind(function() { ++ this._flagFocal = true; ++ }, this)); ++ ++ if (_.isNumber(cx)) { ++ this.center.x = cx; ++ } ++ if (_.isNumber(cy)) { ++ this.center.y = cy; ++ } ++ ++ this.focal.copy(this.center); ++ ++ if (_.isNumber(fx)) { ++ this.focal.x = fx; ++ } ++ if (_.isNumber(fy)) { ++ this.focal.y = fy; ++ } ++ ++ }; ++ ++ _.extend(RadialGradient, { ++ ++ Stop: Two.Gradient.Stop, ++ ++ Properties: [ ++ 'radius' ++ ], ++ ++ MakeObservable: function(object) { ++ ++ Two.Gradient.MakeObservable(object); ++ ++ _.each(RadialGradient.Properties, Two.Utils.defineProperty, object); ++ ++ } ++ ++ }); ++ ++ _.extend(RadialGradient.prototype, Two.Gradient.prototype, { ++ ++ _flagRadius: false, ++ _flagCenter: false, ++ _flagFocal: false, ++ ++ clone: function(parent) { ++ ++ parent = parent || this.parent; ++ ++ var stops = _.map(this.stops, function(stop) { ++ return stop.clone(); ++ }); ++ ++ var clone = new RadialGradient(this.center._x, this.center._y, ++ this._radius, stops, this.focal._x, this.focal._y); ++ ++ _.each(Two.Gradient.Properties.concat(RadialGradient.Properties), function(k) { ++ clone[k] = this[k]; ++ }, this); ++ ++ if (parent) { ++ parent.add(clone); ++ } ++ ++ return clone; ++ ++ }, ++ ++ toObject: function() { ++ ++ var result = Two.Gradient.prototype.toObject.call(this); ++ ++ _.each(RadialGradient.Properties, function(k) { ++ result[k] = this[k]; ++ }, this); ++ ++ result.center = this.center.toObject(); ++ result.focal = this.focal.toObject(); ++ ++ return result; ++ ++ }, ++ ++ _update: function() { ++ ++ if (this._flagRadius || this._flatCenter || this._flagFocal ++ || this._flagSpread || this._flagStops) { ++ this.trigger(Two.Events.change); ++ } ++ ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagRadius = this._flagCenter = this._flagFocal = false; ++ ++ Two.Gradient.prototype.flagReset.call(this); ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ RadialGradient.MakeObservable(RadialGradient.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var _ = Two.Utils; ++ var anchor; ++ var regex = { ++ video: /\.(mp4|webm)$/i, ++ image: /\.(jpe?g|png|gif|tiff)$/i ++ }; ++ ++ if (this.document) { ++ anchor = document.createElement('a'); ++ } ++ ++ var Texture = Two.Texture = function(src, callback) { ++ ++ this._renderer = {}; ++ this._renderer.type = 'texture'; ++ this._renderer.flagOffset = _.bind(Texture.FlagOffset, this); ++ this._renderer.flagScale = _.bind(Texture.FlagScale, this); ++ ++ this.id = Two.Identifier + Two.uniqueId(); ++ this.classList = []; ++ ++ this.offset = new Two.Vector(); ++ ++ if (_.isFunction(callback)) { ++ var loaded = _.bind(function() { ++ this.unbind(Two.Events.load, loaded); ++ if (_.isFunction(callback)) { ++ callback(); ++ } ++ }, this); ++ this.bind(Two.Events.load, loaded); ++ } ++ ++ if (_.isString(src)) { ++ this.src = src; ++ } else if (_.isElement(src)) { ++ this.image = src; ++ } ++ ++ this._update(); ++ ++ }; ++ ++ _.extend(Texture, { ++ ++ Properties: [ ++ 'src', ++ 'loaded', ++ 'repeat' ++ ], ++ ++ ImageRegistry: new Two.Registry(), ++ ++ getAbsoluteURL: function(path) { ++ if (!anchor) { ++ // TODO: Fix for headless environment ++ return path; ++ } ++ anchor.href = path; ++ return anchor.href; ++ }, ++ ++ getImage: function(src) { ++ ++ var absoluteSrc = Texture.getAbsoluteURL(src); ++ ++ if (Texture.ImageRegistry.contains(absoluteSrc)) { ++ return Texture.ImageRegistry.get(absoluteSrc); ++ } ++ ++ var image; ++ ++ if (regex.video.test(absoluteSrc)) { ++ image = document.createElement('video'); ++ } else { ++ image = document.createElement('img'); ++ } ++ ++ image.crossOrigin = 'anonymous'; ++ ++ return image; ++ ++ }, ++ ++ Register: { ++ canvas: function(texture, callback) { ++ texture._src = '#' + texture.id; ++ Texture.ImageRegistry.add(texture.src, texture.image); ++ if (_.isFunction(callback)) { ++ callback(); ++ } ++ }, ++ img: function(texture, callback) { ++ ++ var loaded = function(e) { ++ texture.image.removeEventListener('load', loaded, false); ++ texture.image.removeEventListener('error', error, false); ++ if (_.isFunction(callback)) { ++ callback(); ++ } ++ }; ++ var error = function(e) { ++ texture.image.removeEventListener('load', loaded, false); ++ texture.image.removeEventListener('error', error, false); ++ throw new Two.Utils.Error('unable to load ' + texture.src); ++ }; ++ ++ if (_.isNumber(texture.image.width) && texture.image.width > 0 ++ && _.isNumber(texture.image.height) && texture.image.height > 0) { ++ loaded(); ++ } else { ++ texture.image.addEventListener('load', loaded, false); ++ texture.image.addEventListener('error', error, false); ++ } ++ ++ texture._src = Texture.getAbsoluteURL(texture._src); ++ ++ if (texture.image && texture.image.getAttribute('two-src')) { ++ return; ++ } ++ ++ texture.image.setAttribute('two-src', texture.src); ++ Texture.ImageRegistry.add(texture.src, texture.image); ++ texture.image.src = texture.src; ++ ++ }, ++ video: function(texture, callback) { ++ ++ var loaded = function(e) { ++ texture.image.removeEventListener('load', loaded, false); ++ texture.image.removeEventListener('error', error, false); ++ texture.image.width = texture.image.videoWidth; ++ texture.image.height = texture.image.videoHeight; ++ texture.image.play(); ++ if (_.isFunction(callback)) { ++ callback(); ++ } ++ }; ++ var error = function(e) { ++ texture.image.removeEventListener('load', loaded, false); ++ texture.image.removeEventListener('error', error, false); ++ throw new Two.Utils.Error('unable to load ' + texture.src); ++ }; ++ ++ texture._src = Texture.getAbsoluteURL(texture._src); ++ texture.image.addEventListener('canplaythrough', loaded, false); ++ texture.image.addEventListener('error', error, false); ++ ++ if (texture.image && texture.image.getAttribute('two-src')) { ++ return; ++ } ++ ++ texture.image.setAttribute('two-src', texture.src); ++ Texture.ImageRegistry.add(texture.src, texture.image); ++ texture.image.src = texture.src; ++ texture.image.loop = true; ++ texture.image.load(); ++ ++ } ++ }, ++ ++ load: function(texture, callback) { ++ ++ var src = texture.src; ++ var image = texture.image; ++ var tag = image && image.nodeName.toLowerCase(); ++ ++ if (texture._flagImage) { ++ if (/canvas/i.test(tag)) { ++ Texture.Register.canvas(texture, callback); ++ } else { ++ texture._src = image.getAttribute('two-src') || image.src; ++ Texture.Register[tag](texture, callback); ++ } ++ } ++ ++ if (texture._flagSrc) { ++ if (!image) { ++ texture.image = Texture.getImage(texture.src); ++ } ++ tag = texture.image.nodeName.toLowerCase(); ++ Texture.Register[tag](texture, callback); ++ } ++ ++ }, ++ ++ FlagOffset: function() { ++ this._flagOffset = true; ++ }, ++ ++ FlagScale: function() { ++ this._flagScale = true; ++ }, ++ ++ MakeObservable: function(object) { ++ ++ _.each(Texture.Properties, Two.Utils.defineProperty, object); ++ ++ Object.defineProperty(object, 'image', { ++ enumerable: true, ++ get: function() { ++ return this._image; ++ }, ++ set: function(image) { ++ ++ var tag = image && image.nodeName.toLowerCase(); ++ var index; ++ ++ switch (tag) { ++ case 'canvas': ++ index = '#' + image.id; ++ break; ++ default: ++ index = image.src; ++ } ++ ++ if (Texture.ImageRegistry.contains(index)) { ++ this._image = Texture.ImageRegistry.get(image.src); ++ } else { ++ this._image = image; ++ } ++ ++ this._flagImage = true; ++ ++ } ++ ++ }); ++ ++ Object.defineProperty(object, 'offset', { ++ enumerable: true, ++ get: function() { ++ return this._offset; ++ }, ++ set: function(v) { ++ if (this._offset) { ++ this._offset.unbind(Two.Events.change, this._renderer.flagOffset); ++ } ++ this._offset = v; ++ this._offset.bind(Two.Events.change, this._renderer.flagOffset); ++ this._flagOffset = true; ++ } ++ }); ++ ++ Object.defineProperty(object, 'scale', { ++ enumerable: true, ++ get: function() { ++ return this._scale; ++ }, ++ set: function(v) { ++ ++ if (this._scale instanceof Two.Vector) { ++ this._scale.unbind(Two.Events.change, this._renderer.flagScale); ++ } ++ ++ this._scale = v; ++ ++ if (this._scale instanceof Two.Vector) { ++ this._scale.bind(Two.Events.change, this._renderer.flagScale); ++ } ++ ++ this._flagScale = true; ++ ++ } ++ }); ++ ++ } ++ ++ }); ++ ++ _.extend(Texture.prototype, Two.Utils.Events, Two.Shape.prototype, { ++ ++ _flagSrc: false, ++ _flagImage: false, ++ _flagVideo: false, ++ _flagLoaded: false, ++ _flagRepeat: false, ++ ++ _flagOffset: false, ++ _flagScale: false, ++ ++ _src: '', ++ _image: null, ++ _loaded: false, ++ _repeat: 'no-repeat', ++ ++ _scale: 1, ++ _offset: null, ++ ++ clone: function() { ++ return new Texture(this.src); ++ }, ++ ++ toObject: function() { ++ return { ++ src: this.src, ++ image: this.image ++ } ++ }, ++ ++ _update: function() { ++ ++ if (this._flagSrc || this._flagImage || this._flagVideo) { ++ ++ this.trigger(Two.Events.change); ++ ++ if (this._flagSrc || this._flagImage) { ++ this.loaded = false; ++ Texture.load(this, _.bind(function() { ++ this.loaded = true; ++ this ++ .trigger(Two.Events.change) ++ .trigger(Two.Events.load); ++ }, this)); ++ } ++ ++ } ++ ++ if (this._image && this._image.readyState >= 4) { ++ this._flagVideo = true; ++ } ++ ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagSrc = this._flagImage = this._flagLoaded ++ = this._flagVideo = this._flagScale = this._flagOffset = false; ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ Texture.MakeObservable(Texture.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var _ = Two.Utils; ++ var Path = Two.Path; ++ var Rectangle = Two.Rectangle; ++ ++ var Sprite = Two.Sprite = function(path, ox, oy, cols, rows, frameRate) { ++ ++ Path.call(this, [ ++ new Two.Anchor(), ++ new Two.Anchor(), ++ new Two.Anchor(), ++ new Two.Anchor() ++ ], true); ++ ++ this.noStroke(); ++ this.noFill(); ++ ++ if (path instanceof Two.Texture) { ++ this.texture = path; ++ } else if (_.isString(path)) { ++ this.texture = new Two.Texture(path); ++ } ++ ++ this._update(); ++ this.translation.set(ox || 0, oy || 0); ++ ++ if (_.isNumber(cols)) { ++ this.columns = cols; ++ } ++ if (_.isNumber(rows)) { ++ this.rows = rows; ++ } ++ if (_.isNumber(frameRate)) { ++ this.frameRate = frameRate; ++ } ++ ++ }; ++ ++ _.extend(Sprite, { ++ ++ Properties: [ ++ 'texture', 'columns', 'rows', 'frameRate', 'index' ++ ], ++ ++ MakeObservable: function(obj) { ++ ++ Rectangle.MakeObservable(obj); ++ _.each(Sprite.Properties, Two.Utils.defineProperty, obj); ++ ++ } ++ ++ }) ++ ++ _.extend(Sprite.prototype, Rectangle.prototype, { ++ ++ _flagTexture: false, ++ _flagColumns: false, ++ _flagRows: false, ++ _flagFrameRate: false, ++ flagIndex: false, ++ ++ // Private variables ++ _amount: 1, ++ _duration: 0, ++ _startTime: 0, ++ _playing: false, ++ _firstFrame: 0, ++ _lastFrame: 0, ++ _loop: true, ++ ++ // Exposed through getter-setter ++ _texture: null, ++ _columns: 1, ++ _rows: 1, ++ _frameRate: 0, ++ _index: 0, ++ ++ play: function(firstFrame, lastFrame, onLastFrame) { ++ ++ this._playing = true; ++ this._firstFrame = 0; ++ this._lastFrame = this.amount - 1; ++ this._startTime = _.performance.now(); ++ ++ if (_.isNumber(firstFrame)) { ++ this._firstFrame = firstFrame; ++ } ++ if (_.isNumber(lastFrame)) { ++ this._lastFrame = lastFrame; ++ } ++ if (_.isFunction(onLastFrame)) { ++ this._onLastFrame = onLastFrame; ++ } else { ++ delete this._onLastFrame; ++ } ++ ++ if (this._index !== this._firstFrame) { ++ this._startTime -= 1000 * Math.abs(this._index - this._firstFrame) ++ / this._frameRate; ++ } ++ ++ return this; ++ ++ }, ++ ++ pause: function() { ++ ++ this._playing = false; ++ return this; ++ ++ }, ++ ++ stop: function() { ++ ++ this._playing = false; ++ this._index = 0; ++ ++ return this; ++ ++ }, ++ ++ clone: function(parent) { ++ ++ parent = parent || this.parent; ++ ++ var clone = new Sprite( ++ this.texture, this.translation.x, this.translation.y, ++ this.columns, this.rows, this.frameRate ++ ); ++ ++ if (this.playing) { ++ clone.play(this._firstFrame, this._lastFrame); ++ clone._loop = this._loop; ++ } ++ ++ if (parent) { ++ parent.add(clone); ++ } ++ ++ return clone; ++ ++ }, ++ ++ _update: function() { ++ ++ var effect = this._texture; ++ var cols = this._columns; ++ var rows = this._rows; ++ ++ var width, height, elapsed, amount, duration; ++ var index, iw, ih, isRange, frames; ++ ++ if (this._flagColumns || this._flagRows) { ++ this._amount = this._columns * this._rows; ++ } ++ ++ if (this._flagFrameRate) { ++ this._duration = 1000 * this._amount / this._frameRate; ++ } ++ ++ if (this._flagTexture) { ++ this.fill = this._texture; ++ } ++ ++ if (this._texture.loaded) { ++ ++ iw = effect.image.width; ++ ih = effect.image.height; ++ ++ width = iw / cols; ++ height = ih / rows; ++ amount = this._amount; ++ ++ if (this.width !== width) { ++ this.width = width; ++ } ++ if (this.height !== height) { ++ this.height = height; ++ } ++ ++ if (this._playing && this._frameRate > 0) { ++ ++ if (_.isNaN(this._lastFrame)) { ++ this._lastFrame = amount - 1; ++ } ++ ++ // TODO: Offload perf logic to instance of `Two`. ++ elapsed = _.performance.now() - this._startTime; ++ frames = this._lastFrame + 1; ++ duration = 1000 * (frames - this._firstFrame) / this._frameRate; ++ ++ if (this._loop) { ++ elapsed = elapsed % duration; ++ } else { ++ elapsed = Math.min(elapsed, duration); ++ } ++ ++ index = _.lerp(this._firstFrame, frames, elapsed / duration); ++ index = Math.floor(index); ++ ++ if (index !== this._index) { ++ this._index = index; ++ if (index >= this._lastFrame - 1 && this._onLastFrame) { ++ this._onLastFrame(); // Shortcut for chainable sprite animations ++ } ++ } ++ ++ } ++ ++ var col = this._index % cols; ++ var row = Math.floor(this._index / cols); ++ ++ var ox = - width * col + (iw - width) / 2; ++ var oy = - height * row + (ih - height) / 2; ++ ++ // TODO: Improve performance ++ if (ox !== effect.offset.x) { ++ effect.offset.x = ox; ++ } ++ if (oy !== effect.offset.y) { ++ effect.offset.y = oy; ++ } ++ ++ } ++ ++ Rectangle.prototype._update.call(this); ++ ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagTexture = this._flagColumns = this._flagRows ++ = this._flagFrameRate = false; ++ ++ Rectangle.prototype.flagReset.call(this); ++ ++ return this; ++ } ++ ++ ++ }); ++ ++ Sprite.MakeObservable(Sprite.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ var _ = Two.Utils; ++ var Path = Two.Path; ++ var Rectangle = Two.Rectangle; ++ ++ var ImageSequence = Two.ImageSequence = function(paths, ox, oy, frameRate) { ++ ++ Path.call(this, [ ++ new Two.Anchor(), ++ new Two.Anchor(), ++ new Two.Anchor(), ++ new Two.Anchor() ++ ], true); ++ ++ this._renderer.flagTextures = _.bind(ImageSequence.FlagTextures, this); ++ this._renderer.bindTextures = _.bind(ImageSequence.BindTextures, this); ++ this._renderer.unbindTextures = _.bind(ImageSequence.UnbindTextures, this); ++ ++ this.noStroke(); ++ this.noFill(); ++ ++ this.textures = _.map(paths, ImageSequence.GenerateTexture, this); ++ ++ this._update(); ++ this.translation.set(ox || 0, oy || 0); ++ ++ if (_.isNumber(frameRate)) { ++ this.frameRate = frameRate; ++ } else { ++ this.frameRate = ImageSequence.DefaultFrameRate; ++ } ++ ++ }; ++ ++ _.extend(ImageSequence, { ++ ++ Properties: [ ++ 'frameRate', ++ 'index' ++ ], ++ ++ DefaultFrameRate: 30, ++ ++ FlagTextures: function() { ++ this._flagTextures = true; ++ }, ++ ++ BindTextures: function(items) { ++ ++ var i = items.length; ++ while (i--) { ++ items[i].bind(Two.Events.change, this._renderer.flagTextures); ++ } ++ ++ this._renderer.flagTextures(); ++ ++ }, ++ ++ UnbindTextures: function(items) { ++ ++ var i = items.length; ++ while (i--) { ++ items[i].unbind(Two.Events.change, this._renderer.flagTextures); ++ } ++ ++ this._renderer.flagTextures(); ++ ++ }, ++ ++ MakeObservable: function(obj) { ++ ++ Rectangle.MakeObservable(obj); ++ _.each(ImageSequence.Properties, Two.Utils.defineProperty, obj); ++ ++ Object.defineProperty(obj, 'textures', { ++ ++ enumerable: true, ++ ++ get: function() { ++ return this._textures; ++ }, ++ ++ set: function(textures) { ++ ++ var updateTextures = this._renderer.flagTextures; ++ var bindTextures = this._renderer.bindTextures; ++ var unbindTextures = this._renderer.unbindTextures; ++ ++ // Remove previous listeners ++ if (this._textures) { ++ this._textures ++ .unbind(Two.Events.insert, bindTextures) ++ .unbind(Two.Events.remove, unbindTextures); ++ } ++ ++ // Create new Collection with copy of vertices ++ this._textures = new Two.Utils.Collection((textures || []).slice(0)); ++ ++ // Listen for Collection changes and bind / unbind ++ this._textures ++ .bind(Two.Events.insert, bindTextures) ++ .bind(Two.Events.remove, unbindTextures); ++ ++ // Bind Initial Textures ++ bindTextures(this._textures); ++ ++ } ++ ++ }); ++ ++ }, ++ ++ GenerateTexture: function(obj) { ++ if (obj instanceof Two.Texture) { ++ return obj; ++ } else if (_.isString(obj)) { ++ return new Two.Texture(obj); ++ } ++ } ++ ++ }); ++ ++ _.extend(ImageSequence.prototype, Rectangle.prototype, { ++ ++ _flagTextures: false, ++ _flagFrameRate: false, ++ _flagIndex: false, ++ ++ // Private variables ++ _amount: 1, ++ _duration: 0, ++ _index: 0, ++ _startTime: 0, ++ _playing: false, ++ _firstFrame: 0, ++ _lastFrame: 0, ++ _loop: true, ++ ++ // Exposed through getter-setter ++ _textures: null, ++ _frameRate: 0, ++ ++ play: function(firstFrame, lastFrame, onLastFrame) { ++ ++ this._playing = true; ++ this._firstFrame = 0; ++ this._lastFrame = this.amount - 1; ++ this._startTime = _.performance.now(); ++ ++ if (_.isNumber(firstFrame)) { ++ this._firstFrame = firstFrame; ++ } ++ if (_.isNumber(lastFrame)) { ++ this._lastFrame = lastFrame; ++ } ++ if (_.isFunction(onLastFrame)) { ++ this._onLastFrame = onLastFrame; ++ } else { ++ delete this._onLastFrame; ++ } ++ ++ if (this._index !== this._firstFrame) { ++ this._startTime -= 1000 * Math.abs(this._index - this._firstFrame) ++ / this._frameRate; ++ } ++ ++ return this; ++ ++ }, ++ ++ pause: function() { ++ ++ this._playing = false; ++ return this; ++ ++ }, ++ ++ stop: function() { ++ ++ this._playing = false; ++ this._index = 0; ++ ++ return this; ++ ++ }, ++ ++ clone: function(parent) { ++ ++ parent = parent || this.parent; ++ ++ var clone = new ImageSequence(this.textures, this.translation.x, ++ this.translation.y, this.frameRate) ++ ++ clone._loop = this._loop; ++ ++ if (this._playing) { ++ clone.play(); ++ } ++ ++ if (parent) { ++ parent.add(clone); ++ } ++ ++ return clone; ++ ++ }, ++ ++ _update: function() { ++ ++ var effects = this._textures; ++ var width, height, elapsed, amount, duration, texture; ++ var index, frames; ++ ++ if (this._flagTextures) { ++ this._amount = effects.length; ++ } ++ ++ if (this._flagFrameRate) { ++ this._duration = 1000 * this._amount / this._frameRate; ++ } ++ ++ if (this._playing && this._frameRate > 0) { ++ ++ amount = this._amount; ++ ++ if (_.isNaN(this._lastFrame)) { ++ this._lastFrame = amount - 1; ++ } ++ ++ // TODO: Offload perf logic to instance of `Two`. ++ elapsed = _.performance.now() - this._startTime; ++ frames = this._lastFrame + 1; ++ duration = 1000 * (frames - this._firstFrame) / this._frameRate; ++ ++ if (this._loop) { ++ elapsed = elapsed % duration; ++ } else { ++ elapsed = Math.min(elapsed, duration); ++ } ++ ++ index = _.lerp(this._firstFrame, frames, elapsed / duration); ++ index = Math.floor(index); ++ ++ if (index !== this._index) { ++ ++ this._index = index; ++ texture = effects[this._index]; ++ ++ if (texture.loaded) { ++ ++ width = texture.image.width; ++ height = texture.image.height; ++ ++ if (this.width !== width) { ++ this.width = width; ++ } ++ if (this.height !== height) { ++ this.height = height; ++ } ++ ++ this.fill = texture; ++ ++ if (index >= this._lastFrame - 1 && this._onLastFrame) { ++ this._onLastFrame(); // Shortcut for chainable sprite animations ++ } ++ ++ } ++ ++ } ++ ++ } else if (this._flagIndex || !(this.fill instanceof Two.Texture)) { ++ ++ texture = effects[this._index]; ++ ++ if (texture.loaded) { ++ ++ width = texture.image.width; ++ height = texture.image.height; ++ ++ if (this.width !== width) { ++ this.width = width; ++ } ++ if (this.height !== height) { ++ this.height = height; ++ } ++ ++ } ++ ++ this.fill = texture; ++ ++ } ++ ++ Rectangle.prototype._update.call(this); ++ ++ return this; ++ ++ }, ++ ++ flagReset: function() { ++ ++ this._flagTextures = this._flagFrameRate = false; ++ Rectangle.prototype.flagReset.call(this); ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ ImageSequence.MakeObservable(ImageSequence.prototype); ++ ++})((typeof global !== 'undefined' ? global : this).Two); ++ ++(function(Two) { ++ ++ /** ++ * Constants ++ */ ++ var min = Math.min, max = Math.max; ++ var _ = Two.Utils; ++ ++ /** ++ * A children collection which is accesible both by index and by object id ++ * @constructor ++ */ ++ var Children = function() { ++ ++ Two.Utils.Collection.apply(this, arguments); ++ ++ Object.defineProperty(this, '_events', { ++ value : {}, ++ enumerable: false ++ }); ++ ++ this.ids = {}; ++ ++ this.on(Two.Events.insert, this.attach); ++ this.on(Two.Events.remove, this.detach); ++ Children.prototype.attach.apply(this, arguments); ++ ++ }; ++ ++ Children.prototype = new Two.Utils.Collection(); ++ Children.prototype.constructor = Children; ++ ++ _.extend(Children.prototype, { ++ ++ attach: function(children) { ++ for (var i = 0; i < children.length; i++) { ++ this.ids[children[i].id] = children[i]; ++ } ++ return this; ++ }, ++ ++ detach: function(children) { ++ for (var i = 0; i < children.length; i++) { ++ delete this.ids[children[i].id]; ++ } ++ return this; ++ } ++ ++ }); ++ ++ var Group = Two.Group = function() { ++ ++ Two.Shape.call(this, true); ++ ++ this._renderer.type = 'group'; ++ ++ this.additions = []; ++ this.subtractions = []; ++ ++ this.children = arguments; ++ ++ }; ++ ++ _.extend(Group, { ++ ++ Children: Children, ++ ++ InsertChildren: function(children) { ++ for (var i = 0; i < children.length; i++) { ++ replaceParent.call(this, children[i], this); ++ } ++ }, ++ ++ RemoveChildren: function(children) { ++ for (var i = 0; i < children.length; i++) { ++ replaceParent.call(this, children[i]); ++ } ++ }, ++ ++ OrderChildren: function(children) { ++ this._flagOrder = true; ++ }, ++ ++ MakeObservable: function(object) { ++ ++ var properties = Two.Path.Properties.slice(0); ++ var oi = _.indexOf(properties, 'opacity'); ++ ++ if (oi >= 0) { ++ ++ properties.splice(oi, 1); ++ ++ Object.defineProperty(object, 'opacity', { ++ ++ enumerable: true, ++ ++ get: function() { ++ return this._opacity; ++ }, ++ ++ set: function(v) { ++ // Only set flag if there is an actual difference ++ this._flagOpacity = (this._opacity != v); ++ this._opacity = v; ++ } ++ ++ }); ++ ++ } ++ ++ Two.Shape.MakeObservable(object); ++ Group.MakeGetterSetters(object, properties); ++ ++ Object.defineProperty(object, 'children', { ++ ++ enumerable: true, ++ ++ get: function() { ++ return this._children; ++ }, ++ ++ set: function(children) { ++ ++ var insertChildren = _.bind(Group.InsertChildren, this); ++ var removeChildren = _.bind(Group.RemoveChildren, this); ++ var orderChildren = _.bind(Group.OrderChildren, this); ++ ++ if (this._children) { ++ this._children.unbind(); ++ } ++ ++ this._children = new Children(children); ++ this._children.bind(Two.Events.insert, insertChildren); ++ this._children.bind(Two.Events.remove, removeChildren); ++ this._children.bind(Two.Events.order, orderChildren); ++ ++ } ++ ++ }); ++ ++ Object.defineProperty(object, 'mask', { ++ ++ enumerable: true, ++ ++ get: function() { ++ return this._mask; ++ }, ++ ++ set: function(v) { ++ this._mask = v; ++ this._flagMask = true; ++ if (!v.clip) { ++ v.clip = true; ++ } ++ } ++ ++ }); ++ ++ }, ++ ++ MakeGetterSetters: function(group, properties) { ++ ++ if (!_.isArray(properties)) { ++ properties = [properties]; ++ } ++ ++ _.each(properties, function(k) { ++ Group.MakeGetterSetter(group, k); ++ }); ++ ++ }, ++ ++ MakeGetterSetter: function(group, k) { ++ ++ var secret = '_' + k; ++ ++ Object.defineProperty(group, k, { ++ ++ enumerable: true, ++ ++ get: function() { ++ return this[secret]; ++ }, ++ ++ set: function(v) { ++ this[secret] = v; ++ _.each(this.children, function(child) { // Trickle down styles ++ child[k] = v; ++ }); ++ } ++ ++ }); ++ ++ } ++ ++ }); ++ ++ _.extend(Group.prototype, Two.Shape.prototype, { ++ ++ // Flags ++ // http://en.wikipedia.org/wiki/Flag ++ ++ _flagAdditions: false, ++ _flagSubtractions: false, ++ _flagOrder: false, ++ _flagOpacity: true, ++ ++ _flagMask: false, ++ ++ // Underlying Properties ++ ++ _fill: '#fff', ++ _stroke: '#000', ++ _linewidth: 1.0, ++ _opacity: 1.0, ++ _visible: true, ++ ++ _cap: 'round', ++ _join: 'round', ++ _miter: 4, ++ ++ _closed: true, ++ _curved: false, ++ _automatic: true, ++ _beginning: 0, ++ _ending: 1.0, ++ ++ _mask: null, ++ ++ /** ++ * TODO: Group has a gotcha in that it's at the moment required to be bound to ++ * an instance of two in order to add elements correctly. This needs to ++ * be rethought and fixed. ++ */ ++ clone: function(parent) { ++ ++ parent = parent || this.parent; ++ ++ var group = new Group(); ++ var children = _.map(this.children, function(child) { ++ return child.clone(group); ++ }); ++ ++ group.add(children); ++ ++ group.opacity = this.opacity; ++ ++ if (this.mask) { ++ group.mask = this.mask; ++ } ++ ++ group.translation.copy(this.translation); ++ group.rotation = this.rotation; ++ group.scale = this.scale; ++ ++ if (parent) { ++ parent.add(group); ++ } ++ ++ return group; ++ ++ }, ++ ++ /** ++ * Export the data from the instance of Two.Group into a plain JavaScript ++ * object. This also makes all children plain JavaScript objects. Great ++ * for turning into JSON and storing in a database. ++ */ ++ toObject: function() { ++ ++ var result = { ++ children: [], ++ translation: this.translation.toObject(), ++ rotation: this.rotation, ++ scale: this.scale, ++ opacity: this.opacity, ++ mask: (this.mask ? this.mask.toObject() : null) ++ }; ++ ++ _.each(this.children, function(child, i) { ++ result.children[i] = child.toObject(); ++ }, this); ++ ++ return result; ++ ++ }, ++ ++ /** ++ * Anchor all children to the upper left hand corner ++ * of the group. ++ */ ++ corner: function() { ++ ++ var rect = this.getBoundingClientRect(true), ++ corner = { x: rect.left, y: rect.top }; ++ ++ this.children.forEach(function(child) { ++ child.translation.subSelf(corner); ++ }); ++ ++ return this; ++ ++ }, ++ ++ /** ++ * Anchors all children around the center of the group, ++ * effectively placing the shape around the unit circle. ++ */ ++ center: function() { ++ ++ var rect = this.getBoundingClientRect(true); ++ ++ rect.centroid = { ++ x: rect.left + rect.width / 2, ++ y: rect.top + rect.height / 2 ++ }; ++ ++ this.children.forEach(function(child) { ++ if (child.isShape) { ++ child.translation.subSelf(rect.centroid); ++ } ++ }); ++ ++ // this.translation.copy(rect.centroid); ++ ++ return this; ++ ++ }, ++ ++ /** ++ * Recursively search for id. Returns the first element found. ++ * Returns null if none found. ++ */ ++ getById: function (id) { ++ var search = function (node, id) { ++ if (node.id === id) { ++ return node; ++ } else if (node.children) { ++ var i = node.children.length; ++ while (i--) { ++ var found = search(node.children[i], id); ++ if (found) return found; ++ } ++ } ++ ++ }; ++ return search(this, id) || null; ++ }, ++ ++ /** ++ * Recursively search for classes. Returns an array of matching elements. ++ * Empty array if none found. ++ */ ++ getByClassName: function (cl) { ++ var found = []; ++ var search = function (node, cl) { ++ if (node.classList.indexOf(cl) != -1) { ++ found.push(node); ++ } else if (node.children) { ++ node.children.forEach(function (child) { ++ search(child, cl); ++ }); ++ } ++ return found; ++ }; ++ return search(this, cl); ++ }, ++ ++ /** ++ * Recursively search for children of a specific type, ++ * e.g. Two.Polygon. Pass a reference to this type as the param. ++ * Returns an empty array if none found. ++ */ ++ getByType: function(type) { ++ var found = []; ++ var search = function (node, type) { ++ for (var id in node.children) { ++ if (node.children[id] instanceof type) { ++ found.push(node.children[id]); ++ } else if (node.children[id] instanceof Two.Group) { ++ search(node.children[id], type); ++ } ++ } ++ return found; ++ }; ++ return search(this, type); ++ }, ++ ++ /** ++ * Add objects to the group. ++ */ ++ add: function(objects) { ++ ++ // Allow to pass multiple objects either as array or as multiple arguments ++ // If it's an array also create copy of it in case we're getting passed ++ // a childrens array directly. ++ if (!(objects instanceof Array)) { ++ objects = _.toArray(arguments); ++ } else { ++ objects = objects.slice(); ++ } ++ ++ // Add the objects ++ for (var i = 0; i < objects.length; i++) { ++ if (!(objects[i] && objects[i].id)) continue; ++ this.children.push(objects[i]); ++ } ++ ++ return this; ++ ++ }, ++ ++ /** ++ * Remove objects from the group. ++ */ ++ remove: function(objects) { ++ ++ var l = arguments.length, ++ grandparent = this.parent; ++ ++ // Allow to call remove without arguments ++ // This will detach the object from the scene. ++ if (l <= 0 && grandparent) { ++ grandparent.remove(this); ++ return this; ++ } ++ ++ // Allow to pass multiple objects either as array or as multiple arguments ++ // If it's an array also create copy of it in case we're getting passed ++ // a childrens array directly. ++ if (!(objects instanceof Array)) { ++ objects = _.toArray(arguments); ++ } else { ++ objects = objects.slice(); ++ } ++ ++ // Remove the objects ++ for (var i = 0; i < objects.length; i++) { ++ if (!objects[i] || !(this.children.ids[objects[i].id])) continue; ++ this.children.splice(_.indexOf(this.children, objects[i]), 1); ++ } ++ ++ return this; ++ ++ }, ++ ++ /** ++ * Return an object with top, left, right, bottom, width, and height ++ * parameters of the group. ++ */ ++ getBoundingClientRect: function(shallow) { ++ var rect; ++ ++ // TODO: Update this to not __always__ update. Just when it needs to. ++ this._update(true); ++ ++ // Variables need to be defined here, because of nested nature of groups. ++ var left = Infinity, right = -Infinity, ++ top = Infinity, bottom = -Infinity; ++ ++ this.children.forEach(function(child) { ++ ++ if (/(linear-gradient|radial-gradient|gradient)/.test(child._renderer.type)) { ++ return; ++ } ++ ++ rect = child.getBoundingClientRect(shallow); ++ ++ if (!_.isNumber(rect.top) || !_.isNumber(rect.left) || ++ !_.isNumber(rect.right) || !_.isNumber(rect.bottom)) { ++ return; ++ } ++ ++ top = min(rect.top, top); ++ left = min(rect.left, left); ++ right = max(rect.right, right); ++ bottom = max(rect.bottom, bottom); ++ ++ }, this); ++ ++ return { ++ top: top, ++ left: left, ++ right: right, ++ bottom: bottom, ++ width: right - left, ++ height: bottom - top ++ }; ++ ++ }, ++ ++ /** ++ * Trickle down of noFill ++ */ ++ noFill: function() { ++ this.children.forEach(function(child) { ++ child.noFill(); ++ }); ++ return this; ++ }, ++ ++ /** ++ * Trickle down of noStroke ++ */ ++ noStroke: function() { ++ this.children.forEach(function(child) { ++ child.noStroke(); ++ }); ++ return this; ++ }, ++ ++ /** ++ * Trickle down subdivide ++ */ ++ subdivide: function() { ++ var args = arguments; ++ this.children.forEach(function(child) { ++ child.subdivide.apply(child, args); ++ }); ++ return this; ++ }, ++ ++ flagReset: function() { ++ ++ if (this._flagAdditions) { ++ this.additions.length = 0; ++ this._flagAdditions = false; ++ } ++ ++ if (this._flagSubtractions) { ++ this.subtractions.length = 0; ++ this._flagSubtractions = false; ++ } ++ ++ this._flagOrder = this._flagMask = this._flagOpacity = false; ++ ++ Two.Shape.prototype.flagReset.call(this); ++ ++ return this; ++ ++ } ++ ++ }); ++ ++ Group.MakeObservable(Group.prototype); ++ ++ /** ++ * Helper function used to sync parent-child relationship within the ++ * `Two.Group.children` object. ++ * ++ * Set the parent of the passed object to another object ++ * and updates parent-child relationships ++ * Calling with one arguments will simply remove the parenting ++ */ ++ function replaceParent(child, newParent) { ++ ++ var parent = child.parent; ++ var index; ++ ++ if (parent === newParent) { ++ this.additions.push(child); ++ this._flagAdditions = true; ++ return; ++ } ++ ++ if (parent && parent.children.ids[child.id]) { ++ ++ index = _.indexOf(parent.children, child); ++ parent.children.splice(index, 1); ++ ++ // If we're passing from one parent to another... ++ index = _.indexOf(parent.additions, child); ++ ++ if (index >= 0) { ++ parent.additions.splice(index, 1); ++ } else { ++ parent.subtractions.push(child); ++ parent._flagSubtractions = true; ++ } ++ ++ } ++ ++ if (newParent) { ++ child.parent = newParent; ++ this.additions.push(child); ++ this._flagAdditions = true; ++ return; ++ } ++ ++ // If we're passing from one parent to another... ++ index = _.indexOf(this.additions, child); ++ ++ if (index >= 0) { ++ this.additions.splice(index, 1); ++ } else { ++ this.subtractions.push(child); ++ this._flagSubtractions = true; ++ } ++ ++ delete child.parent; ++ ++ } ++ ++})((typeof global !== 'undefined' ? global : this).Two); diff --cc debian/patches/32bit-fixes.patch index 000000000,000000000..cec515eec new file mode 100644 --- /dev/null +++ b/debian/patches/32bit-fixes.patch @@@ -1,0 -1,0 +1,148 @@@ ++Description: Misc fixes for 32 bit architecture builds. ++Author: James Page ++Forwarded: no ++ ++--- a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc +++++ b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc ++@@ -253,7 +253,8 @@ bool Replayer::get_replay_status(std: ++ ++ json_spirit::mObject root_obj; ++ root_obj["replay_state"] = replay_state; ++- root_obj["remote_snapshot_timestamp"] = remote_snap_info->timestamp.sec(); +++ root_obj["remote_snapshot_timestamp"] = static_cast( +++ remote_snap_info->timestamp.sec()); ++ ++ auto matching_remote_snap_id = util::compute_remote_snap_id( ++ m_state_builder->local_image_ctx->image_lock, ++@@ -267,8 +268,8 @@ bool Replayer::get_replay_status(std: ++ // use the timestamp from the matching remote image since ++ // the local snapshot would just be the time the snapshot was ++ // synced and not the consistency point in time. ++- root_obj["local_snapshot_timestamp"] = ++- matching_remote_snap_it->second.timestamp.sec(); +++ root_obj["local_snapshot_timestamp"] = static_cast( +++ matching_remote_snap_it->second.timestamp.sec()); ++ } ++ ++ matching_remote_snap_it = m_state_builder->remote_image_ctx->snap_info.find( ++@@ -276,7 +277,8 @@ bool Replayer::get_replay_status(std: ++ if (m_remote_snap_id_end != CEPH_NOSNAP && ++ matching_remote_snap_it != ++ m_state_builder->remote_image_ctx->snap_info.end()) { ++- root_obj["syncing_snapshot_timestamp"] = remote_snap_info->timestamp.sec(); +++ root_obj["syncing_snapshot_timestamp"] = static_cast( +++ remote_snap_info->timestamp.sec()); ++ root_obj["syncing_percent"] = static_cast( ++ 100 * m_local_mirror_snap_ns.last_copied_object_number / ++ static_cast(std::max(1U, m_local_object_count))); ++--- a/src/common/buffer.cc +++++ b/src/common/buffer.cc ++@@ -2272,7 +2272,7 @@ MEMPOOL_DEFINE_OBJECT_FACTORY(buffer::ra ++ ++ void ceph::buffer::list::page_aligned_appender::_refill(size_t len) { ++ const size_t alloc = \ ++- std::max((size_t)min_alloc, (len + CEPH_PAGE_SIZE - 1) & CEPH_PAGE_MASK); +++ std::max((size_t)min_alloc, (size_t)((len + CEPH_PAGE_SIZE - 1) & CEPH_PAGE_MASK)); ++ auto new_back = \ ++ ptr_node::create(buffer::create_page_aligned(alloc)); ++ new_back->set_length(0); // unused, so far. ++--- a/src/s3select/include/s3select_functions.h +++++ b/src/s3select/include/s3select_functions.h ++@@ -585,7 +585,7 @@ struct _fn_diff_timestamp : public base_ ++ { ++ boost::gregorian::date_period dp = ++ boost::gregorian::date_period( val_dt1.timestamp()->date(), val_dt2.timestamp()->date()); ++- result->set_value( dp.length().days() ); +++ result->set_value( (int64_t)dp.length().days() ); ++ } ++ else if (strcmp(val_date_part.str(), "hours") == 0) ++ { ++--- a/src/os/bluestore/BlueFS.cc +++++ b/src/os/bluestore/BlueFS.cc ++@@ -3787,11 +3787,11 @@ int BlueFS::do_replay_recovery_read(File ++ ++ size_t BlueFS::probe_alloc_avail(int dev, uint64_t alloc_size) ++ { ++- size_t total = 0; ++- auto iterated_allocation = [&](size_t off, size_t len) { +++ uint64_t total = 0; +++ auto iterated_allocation = [&](uint64_t off, uint64_t len) { ++ //only count in size that is alloc_size aligned ++- size_t dist_to_alignment; ++- size_t offset_in_block = off & (alloc_size - 1); +++ uint64_t dist_to_alignment; +++ uint64_t offset_in_block = off & (alloc_size - 1); ++ if (offset_in_block == 0) ++ dist_to_alignment = 0; ++ else ++--- a/src/tools/neorados.cc +++++ b/src/tools/neorados.cc ++@@ -146,7 +146,7 @@ void create(R::RADOS& r, const std::vect ++ obj, pname)); ++ } ++ ++-inline constexpr std::size_t io_size = 4 << 20; +++inline constexpr std::uint64_t io_size = 4 << 20; ++ ++ void write(R::RADOS& r, const std::vector& p, s::yield_context y) ++ { ++@@ -156,7 +156,7 @@ void write(R::RADOS& r, const std::vecto ++ ++ bs::error_code ec; ++ std::unique_ptr buf = std::make_unique(io_size); ++- std::size_t off = 0; +++ std::uint64_t off = 0; ++ boost::io::ios_exception_saver ies(std::cin); ++ ++ std::cin.exceptions(std::istream::badbit); ++@@ -203,7 +203,7 @@ void read(R::RADOS& r, const std::vector ++ obj, pname)); ++ } ++ ++- std::size_t off = 0; +++ std::uint64_t off = 0; ++ ceph::buffer::list bl; ++ while (auto toread = std::max(len - off, io_size)) { ++ R::ReadOp op; ++--- a/src/tools/cephfs_mirror/FSMirror.cc +++++ b/src/tools/cephfs_mirror/FSMirror.cc ++@@ -345,7 +345,7 @@ void FSMirror::handle_acquire_directory( ++ std::scoped_lock locker(m_lock); ++ m_directories.emplace(dir_path); ++ m_service_daemon->add_or_update_fs_attribute(m_filesystem.fscid, SERVICE_DAEMON_DIR_COUNT_KEY, ++- m_directories.size()); +++ static_cast(m_directories.size())); ++ ++ for (auto &[peer, peer_replayer] : m_peer_replayers) { ++ dout(10) << ": peer=" << peer << dendl; ++@@ -363,7 +363,7 @@ void FSMirror::handle_release_directory( ++ if (it != m_directories.end()) { ++ m_directories.erase(it); ++ m_service_daemon->add_or_update_fs_attribute(m_filesystem.fscid, SERVICE_DAEMON_DIR_COUNT_KEY, ++- m_directories.size()); +++ static_cast(m_directories.size())); ++ for (auto &[peer, peer_replayer] : m_peer_replayers) { ++ dout(10) << ": peer=" << peer << dendl; ++ peer_replayer->remove_directory(dir_path); ++--- a/src/librbd/object_map/DiffRequest.cc +++++ b/src/librbd/object_map/DiffRequest.cc ++@@ -175,7 +175,7 @@ void DiffRequest::handle_load_object_ ++ m_object_map.resize(num_objs); ++ } ++ ++- size_t prev_object_diff_state_size = m_object_diff_state->size(); +++ uint64_t prev_object_diff_state_size = m_object_diff_state->size(); ++ if (prev_object_diff_state_size < num_objs) { ++ // the diff state should be the largest of all snapshots in the set ++ m_object_diff_state->resize(num_objs); ++--- a/src/SimpleRADOSStriper.cc +++++ b/src/SimpleRADOSStriper.cc ++@@ -140,7 +140,7 @@ int SimpleRADOSStriper::remove() ++ return 0; ++ } ++ ++-int SimpleRADOSStriper::truncate(uint64_t size) +++int SimpleRADOSStriper::truncate(size_t size) ++ { ++ d(5) << size << dendl; ++ diff --cc debian/patches/add-option-to-disable-ceph-dencoder.patch index 000000000,000000000..911a88fa6 new file mode 100644 --- /dev/null +++ b/debian/patches/add-option-to-disable-ceph-dencoder.patch @@@ -1,0 -1,0 +1,12 @@@ ++Index: ceph/src/tools/CMakeLists.txt ++=================================================================== ++--- ceph.orig/src/tools/CMakeLists.txt +++++ ceph/src/tools/CMakeLists.txt ++@@ -150,5 +150,7 @@ ++ endif() ++ ++ add_subdirectory(immutable_object_cache) +++if(NOT DISABLE_DENCODER) ++ add_subdirectory(ceph-dencoder) +++endif(DISABLE_DENCODER) ++ add_subdirectory(erasure-code) diff --cc debian/patches/bug1914584.patch index 000000000,000000000..50a83f70e new file mode 100644 --- /dev/null +++ b/debian/patches/bug1914584.patch @@@ -1,0 -1,0 +1,47 @@@ ++From a8c1aec073fc8364818027a26fa1ddb5d34c58af Mon Sep 17 00:00:00 2001 ++From: Matthew Vernon ++Date: Thu, 4 Feb 2021 11:41:14 +0000 ++Subject: [PATCH] rgw/radosgw-admin clarify error when email address already in ++ use ++ ++The error message if you try and create an S3 user with an email ++address that is already associated with another S3 account is very ++confusing; this patch makes it much clearer ++ ++To reproduce: ++ ++radosgw-admin user create --uid=foo --display-name="Foo test" --email=bar@domain.invalid ++radosgw-admin user create --uid=test --display-name="AN test" --email=bar@domain.invalid ++could not create user: unable to parse parameters, user id mismatch, operation id: foo does not match: test ++ ++With this patch: ++ ++radosgw-admin user create --uid=test --display-name="AN test" --email=bar@domain.invalid ++could not create user: unable to create user test because user id foo already exists with email bar@domain.invalid ++ ++Fixes: https://tracker.ceph.com/issues/49137 ++Fixes: https://tracker.ceph.com/issues/19411 ++Signed-off-by: Matthew Vernon ++(cherry picked from commit 05318d6f71e45a42a46518a0ef17047dfab83990) ++--- ++ src/rgw/rgw_user.cc | 9 ++++++++- ++ 1 file changed, 8 insertions(+), 1 deletion(-) ++ ++--- a/src/rgw/rgw_user.cc +++++ b/src/rgw/rgw_user.cc ++@@ -1971,7 +1971,14 @@ int RGWUser::remove(const DoutPrefixProv ++ ++ ret = check_op(op_state, &subprocess_msg); ++ if (ret < 0) { ++- set_err_msg(err_msg, "unable to parse parameters, " + subprocess_msg); +++ if (is_populated() && (user_id.compare(op_state.get_user_id()) != 0)) { +++ set_err_msg(err_msg, "unable to create user " + user_id.to_str() +++ + " because user id " + op_state.get_user_id().to_str() +++ + " already exists with email " +++ + op_state.get_user_email()); +++ } else { +++ set_err_msg(err_msg, "unable to parse parameters, " + subprocess_msg); +++ } ++ return ret; ++ } ++ diff --cc debian/patches/bug1917414.patch index 000000000,000000000..aca739fb9 new file mode 100644 --- /dev/null +++ b/debian/patches/bug1917414.patch @@@ -1,0 -1,0 +1,143 @@@ ++From db463aa139aa0f3eb996062bd7c65f0d10a7932b Mon Sep 17 00:00:00 2001 ++From: luo rixin ++Date: Fri, 8 Jan 2021 16:16:02 +0800 ++Subject: [PATCH] src/isa-l/erasure_code: Fix text relocation on aarch64 ++ ++Here is the bug report on ceph. https://tracker.ceph.com/issues/48681 ++ ++Signed-off-by: luo rixin ++--- ++ src/isa-l/erasure_code/aarch64/gf_2vect_mad_neon.S | 5 +++-- ++ src/isa-l/erasure_code/aarch64/gf_3vect_mad_neon.S | 5 +++-- ++ src/isa-l/erasure_code/aarch64/gf_4vect_mad_neon.S | 5 +++-- ++ src/isa-l/erasure_code/aarch64/gf_5vect_mad_neon.S | 5 +++-- ++ src/isa-l/erasure_code/aarch64/gf_6vect_mad_neon.S | 5 +++-- ++ src/isa-l/erasure_code/aarch64/gf_vect_mad_neon.S | 5 +++-- ++ 6 files changed, 18 insertions(+), 12 deletions(-) ++ ++--- a/src/isa-l/erasure_code/aarch64/gf_2vect_mad_neon.S +++++ b/src/isa-l/erasure_code/aarch64/gf_2vect_mad_neon.S ++@@ -360,7 +360,8 @@ gf_2vect_mad_neon: ++ sub x_dest1, x_dest1, x_tmp ++ sub x_dest2, x_dest2, x_tmp ++ ++- ldr x_const, =const_tbl +++ adrp x_const, const_tbl +++ add x_const, x_const, :lo12:const_tbl ++ sub x_const, x_const, x_tmp ++ ldr q_tmp, [x_const, #16] ++ ++@@ -394,7 +395,7 @@ gf_2vect_mad_neon: ++ mov w_ret, #1 ++ ret ++ ++-.section .data +++.section .rodata ++ .balign 8 ++ const_tbl: ++ .dword 0x0000000000000000, 0x0000000000000000 ++--- a/src/isa-l/erasure_code/aarch64/gf_3vect_mad_neon.S +++++ b/src/isa-l/erasure_code/aarch64/gf_3vect_mad_neon.S ++@@ -332,7 +332,8 @@ gf_3vect_mad_neon: ++ sub x_dest2, x_dest2, x_tmp ++ sub x_dest3, x_dest3, x_tmp ++ ++- ldr x_const, =const_tbl +++ adrp x_const, const_tbl +++ add x_const, x_const, :lo12:const_tbl ++ sub x_const, x_const, x_tmp ++ ldr q_tmp, [x_const, #16] ++ ++@@ -374,7 +375,7 @@ gf_3vect_mad_neon: ++ mov w_ret, #1 ++ ret ++ ++-.section .data +++.section .rodata ++ .balign 8 ++ const_tbl: ++ .dword 0x0000000000000000, 0x0000000000000000 ++--- a/src/isa-l/erasure_code/aarch64/gf_4vect_mad_neon.S +++++ b/src/isa-l/erasure_code/aarch64/gf_4vect_mad_neon.S ++@@ -397,7 +397,8 @@ gf_4vect_mad_neon: ++ sub x_dest3, x_dest3, x_tmp ++ sub x_dest4, x_dest4, x_tmp ++ ++- ldr x_const, =const_tbl +++ adrp x_const, const_tbl +++ add x_const, x_const, :lo12:const_tbl ++ sub x_const, x_const, x_tmp ++ ldr q_tmp, [x_const, #16] ++ ++@@ -448,7 +449,7 @@ gf_4vect_mad_neon: ++ mov w_ret, #1 ++ ret ++ ++-.section .data +++.section .rodata ++ .balign 8 ++ const_tbl: ++ .dword 0x0000000000000000, 0x0000000000000000 ++--- a/src/isa-l/erasure_code/aarch64/gf_5vect_mad_neon.S +++++ b/src/isa-l/erasure_code/aarch64/gf_5vect_mad_neon.S ++@@ -463,7 +463,8 @@ gf_5vect_mad_neon: ++ sub x_dest4, x_dest4, x_tmp ++ sub x_dest5, x_dest5, x_tmp ++ ++- ldr x_const, =const_tbl +++ adrp x_const, const_tbl +++ add x_const, x_const, :lo12:const_tbl ++ sub x_const, x_const, x_tmp ++ ldr q_tmp, [x_const, #16] ++ ++@@ -527,7 +528,7 @@ gf_5vect_mad_neon: ++ mov w_ret, #1 ++ ret ++ ++-.section .data +++.section .rodata ++ .balign 8 ++ const_tbl: ++ .dword 0x0000000000000000, 0x0000000000000000 ++--- a/src/isa-l/erasure_code/aarch64/gf_6vect_mad_neon.S +++++ b/src/isa-l/erasure_code/aarch64/gf_6vect_mad_neon.S ++@@ -526,7 +526,8 @@ gf_6vect_mad_neon: ++ sub x_dest5, x_dest5, x_tmp ++ sub x_dest6, x_dest6, x_tmp ++ ++- ldr x_const, =const_tbl +++ adrp x_const, const_tbl +++ add x_const, x_const, :lo12:const_tbl ++ sub x_const, x_const, x_tmp ++ ldr q_tmp, [x_const, #16] ++ ++@@ -602,7 +603,7 @@ gf_6vect_mad_neon: ++ mov w_ret, #1 ++ ret ++ ++-.section .data +++.section .rodata ++ .balign 8 ++ const_tbl: ++ .dword 0x0000000000000000, 0x0000000000000000 ++--- a/src/isa-l/erasure_code/aarch64/gf_vect_mad_neon.S +++++ b/src/isa-l/erasure_code/aarch64/gf_vect_mad_neon.S ++@@ -281,7 +281,8 @@ gf_vect_mad_neon: ++ mov x_src, x_src_end ++ sub x_dest1, x_dest1, x_tmp ++ ++- ldr x_const, =const_tbl +++ adrp x_const, const_tbl +++ add x_const, x_const, :lo12:const_tbl ++ sub x_const, x_const, x_tmp ++ ldr q_tmp, [x_const, #16] ++ ++@@ -307,7 +308,7 @@ gf_vect_mad_neon: ++ mov w_ret, #1 ++ ret ++ ++-.section .data +++.section .rodata ++ .balign 8 ++ const_tbl: ++ .dword 0x0000000000000000, 0x0000000000000000 diff --cc debian/patches/civetweb-755-1.8-somaxconn-configurable.patch index 000000000,000000000..8313b3ece new file mode 100644 --- /dev/null +++ b/debian/patches/civetweb-755-1.8-somaxconn-configurable.patch @@@ -1,0 -1,0 +1,53 @@@ ++Description: Makes SOMAXCONN user-configurable. ++Author: Jesse Williamson ++Origin: upstream, https://github.com/civetweb/civetweb/pull/776/commits/febab7dc38c9671577603425c54c20f841e27f97 ++Bug: https://github.com/civetweb/civetweb/issues/775 ++Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/ceph/+bug/1838109 ++--- ++This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ++--- a/src/civetweb/src/civetweb.c +++++ b/src/civetweb/src/civetweb.c ++@@ -1541,10 +1541,6 @@ typedef int socklen_t; ++ #define MSG_NOSIGNAL (0) ++ #endif ++ ++-#if !defined(SOMAXCONN) ++-#define SOMAXCONN (100) ++-#endif ++- ++ /* Size of the accepted socket queue */ ++ #if !defined(MGSQLEN) ++ #define MGSQLEN (20) ++@@ -2063,6 +2059,7 @@ enum { ++ SSL_CERTIFICATE, ++ SSL_CERTIFICATE_CHAIN, ++ NUM_THREADS, +++ SO_MAX_CONNECTIONS, ++ RUN_AS_USER, ++ URL_REWRITE_PATTERN, ++ HIDE_FILES, ++@@ -2165,6 +2162,7 @@ static struct mg_option config_options[] ++ {"ssl_certificate", CONFIG_TYPE_FILE, NULL}, ++ {"ssl_certificate_chain", CONFIG_TYPE_FILE, NULL}, ++ {"num_threads", CONFIG_TYPE_NUMBER, "50"}, +++ {"max_connections", CONFIG_TYPE_NUMBER, "100"}, ++ {"run_as_user", CONFIG_TYPE_STRING, NULL}, ++ {"url_rewrite_patterns", CONFIG_TYPE_STRING_LIST, NULL}, ++ {"hide_files_patterns", CONFIG_TYPE_EXT_PATTERN, NULL}, ++@@ -13340,7 +13338,15 @@ set_ports_option(struct mg_context *ctx) ++ continue; ++ } ++ ++- if (listen(so.sock, SOMAXCONN) != 0) { +++ char *p = ctx->config[SO_MAX_CONNECTIONS]; +++ long opt_max_connections = strtol(p, NULL, 10); +++ if(opt_max_connections > INT_MAX || opt_max_connections < 1) { +++ mg_cry(fc(ctx), +++ "max_connections value \"%s\" is invalid", p); +++ continue; +++ } +++ +++ if (listen(so.sock, (int)opt_max_connections) != 0) { ++ ++ mg_cry(fc(ctx), ++ "cannot listen to %.*s: %d (%s)", diff --cc debian/patches/civetweb-755-1.8-somaxconn-configurable_conf.patch index 000000000,000000000..e8e3b0b0f new file mode 100644 --- /dev/null +++ b/debian/patches/civetweb-755-1.8-somaxconn-configurable_conf.patch @@@ -1,0 -1,0 +1,18 @@@ ++Description: Adds max_connections to reference configuration. ++Author: Jesse Williamson ++Origin: upstream, https://github.com/civetweb/civetweb/pull/776/commits/3b8eb36676f70d06f8918ccf62029207c49cdda0 ++Bug: https://github.com/civetweb/civetweb/issues/775 ++Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/ceph/+bug/1838109 ++--- ++This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ++--- a/src/civetweb/resources/civetweb.conf +++++ b/src/civetweb/resources/civetweb.conf ++@@ -8,6 +8,8 @@ ++ document_root . ++ listening_ports 8080 ++ +++#so_max_connections 100 +++ ++ # cgi_pattern **.cgi$|**.pl$|**.php$ ++ # cgi_environment ++ # put_delete_auth_file diff --cc debian/patches/civetweb-755-1.8-somaxconn-configurable_test.patch index 000000000,000000000..cdd27b5ab new file mode 100644 --- /dev/null +++ b/debian/patches/civetweb-755-1.8-somaxconn-configurable_test.patch @@@ -1,0 -1,0 +1,17 @@@ ++Description: Adds max_connections to test display. ++Author: Jesse Williamson ++Origin: upstream, https://github.com/civetweb/civetweb/pull/776/commits/3b8eb36676f70d06f8918ccf62029207c49cdda0 ++Bug: https://github.com/civetweb/civetweb/issues/775 ++Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/ceph/+bug/1838109 ++--- ++This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ++--- a/src/civetweb/test/page3.ssjs +++++ b/src/civetweb/test/page3.ssjs ++@@ -21,6 +21,7 @@ opts = [ ++ "document_root", ++ "ssl_certificate", ++ "num_threads", +++"max_connections", ++ "run_as_user", ++ "url_rewrite_patterns", ++ "hide_files_patterns", diff --cc debian/patches/cmake-test-for-16-bytes-atomic-support-on-mips-also.patch index 000000000,000000000..c9712311a new file mode 100644 --- /dev/null +++ b/debian/patches/cmake-test-for-16-bytes-atomic-support-on-mips-also.patch @@@ -1,0 -1,0 +1,29 @@@ ++Description: cmake: test for 16-byte atomic support on mips also ++ it's reported that a mips64el build host is able to pass the test of ++ CheckCxxAtomic without linking against libatomic, while librbd.so ++ fails to link due to failures like ++ . ++ /usr/bin/ld: ../../../lib/librbd.so.1.16.0: undefined reference to `__atomic_store_16' ++ /usr/bin/ld: ../../../lib/librbd.so.1.16.0: undefined reference to `__atomic_load_16' ++ /usr/bin/ld: ../../../lib/librbd.so.1.16.0: undefined reference to `__atomic_compare_exchange_16' ++ . ++ so we have to check the existence of __atomic_load_16 instruction on ++ mips architecture. ++Author: Kefu Chai ++Date: Wed, 24 Nov 2021 00:40:54 +0800 ++Origin: upstream, https://github.com/ceph/ceph/commit/709a77f22010f03aee4a4c0ab930588944cb4a58 ++Last-Update: 2021-11-24 ++ ++diff --git a/cmake/modules/CheckCxxAtomic.cmake b/cmake/modules/CheckCxxAtomic.cmake ++index f2d89cf3e0beb..da2be5206d634 100644 ++--- a/cmake/modules/CheckCxxAtomic.cmake +++++ b/cmake/modules/CheckCxxAtomic.cmake ++@@ -11,7 +11,7 @@ function(check_cxx_atomics var) ++ #include ++ #include ++ ++-#if __s390x__ +++#if defined(__s390x__) || (defined(__mips__) && _MIPS_SIM ==_ABI64 ) ++ // Boost needs 16-byte atomics for tagged pointers. ++ // These are implemented via inline instructions on the platform ++ // if 16-byte alignment can be proven, and are delegated to libatomic diff --cc debian/patches/compile-ppc.c-on-all-powerpc-machines.patch index 000000000,000000000..888d58919 new file mode 100644 --- /dev/null +++ b/debian/patches/compile-ppc.c-on-all-powerpc-machines.patch @@@ -1,0 -1,0 +1,92 @@@ ++From 1b9ad6ca971d2c6222f1fb405ae620a32159cd5d Mon Sep 17 00:00:00 2001 ++From: Kefu Chai ++Date: Sun, 29 Aug 2021 22:24:30 +0800 ++Subject: [PATCH] arch,cmake: compile ppc.c on all powerpc machines ++ ++* cmake/modules/SIMDExt.cmake: define HAVE_PPC for 32-bit PowerPC. ++* src/arch/CMakeLists.txt: compile ppc.c for all PowerPC architectures, ++ including powerpc (32-bit PowerPC), ppc64el (64-bit Little Endian ++ PowerPC) and ppc64 (64-bit Big Endian PowerPC). ++ ++before this change, ppc.c is only compiled if HAVE_POWER8 is defined. ++but Power8 is a 64-bit PowerPC architecture. while in src/arch/probe.cc, ++we check for `defined(__powerpc__) || defined(__ppc__)`, if this is ++true, ceph_arch_ppc_probe() is used to check for the support of ++Altivec. but on non-power8 PowerPC machines, the linker fails to find the ++symbols like ceph_arch_ppc_probe(), as ppc.c is not compiled on them. ++ ++in this change, ppc.c is compiled on all PowerPC architectures, so that ++ceph_arch_ppc_probe() is also available on non-power8 machines. this ++change does not impact the behavior of non-power8 machines. because ++on them, the runtime check would fail to detect the existence of ++PPC_FEATURE2_VEC_CRYPTO instructions. ++ ++Reported-by: Mattias Ellert ++Signed-off-by: Kefu Chai ++--- ++ cmake/modules/SIMDExt.cmake | 17 ++++++++++++++--- ++ src/arch/CMakeLists.txt | 2 +- ++ 2 files changed, 15 insertions(+), 4 deletions(-) ++ ++Index: ceph/cmake/modules/SIMDExt.cmake ++=================================================================== ++--- ceph.orig/cmake/modules/SIMDExt.cmake +++++ ceph/cmake/modules/SIMDExt.cmake ++@@ -1,8 +1,13 @@ ++ # detect SIMD extensions ++ # +++# HAVE_ARM ++ # HAVE_ARMV8_CRC +++# HAVE_ARMV8_CRC_CRYPTO_INTRINSICS +++# HAVE_ARMV8_CRYPTO ++ # HAVE_ARMV8_SIMD ++ # HAVE_ARM_NEON +++# +++# HAVE_INTEL ++ # HAVE_INTEL_SSE ++ # HAVE_INTEL_SSE2 ++ # HAVE_INTEL_SSE3 ++@@ -11,6 +16,10 @@ ++ # HAVE_INTEL_SSE4_1 ++ # HAVE_INTEL_SSE4_2 ++ # +++# HAVE_PPC64LE +++# HAVE_PPC64 +++# HAVE_PPC +++# ++ # SIMD_COMPILE_FLAGS ++ # ++ ++@@ -82,14 +91,16 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i ++ endif() ++ endif(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64") ++ endif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686|amd64|x86_64|AMD64") ++-elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(powerpc|ppc)64|(powerpc|ppc)64le") +++elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(powerpc|ppc)") ++ if(CMAKE_SYSTEM_PROCESSOR MATCHES "(powerpc|ppc)64le") ++ set(HAVE_PPC64LE 1) ++ message(STATUS " we are ppc64le") ++- else() +++ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(powerpc|ppc)64") ++ set(HAVE_PPC64 1) ++ message(STATUS " we are ppc64") ++- endif(CMAKE_SYSTEM_PROCESSOR MATCHES "(powerpc|ppc)64le") +++ else() +++ set(HAVE_PPC 1) +++ endif() ++ CHECK_C_COMPILER_FLAG("-maltivec" HAS_ALTIVEC) ++ if(HAS_ALTIVEC) ++ message(STATUS " HAS_ALTIVEC yes") ++Index: ceph/src/arch/CMakeLists.txt ++=================================================================== ++--- ceph.orig/src/arch/CMakeLists.txt +++++ ceph/src/arch/CMakeLists.txt ++@@ -5,7 +5,7 @@ if(HAVE_ARM) ++ list(APPEND arch_srcs arm.c) ++ elseif(HAVE_INTEL) ++ list(APPEND arch_srcs intel.c) ++-elseif(HAVE_POWER8) +++elseif(HAVE_PPC64LE OR HAVE_PPC64 OR HAVE_PPC) ++ list(APPEND arch_srcs ppc.c) ++ endif() ++ diff --cc debian/patches/debian-armel-armhf-buildflags.patch index 000000000,000000000..e9a450aa5 new file mode 100644 --- /dev/null +++ b/debian/patches/debian-armel-armhf-buildflags.patch @@@ -1,0 -1,0 +1,45 @@@ ++--- a/cmake/modules/SIMDExt.cmake +++++ b/cmake/modules/SIMDExt.cmake ++@@ -40,11 +40,14 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch ++ ++ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|ARM") ++ set(HAVE_ARM 1) ++- CHECK_C_COMPILER_FLAG(-mfpu=neon HAVE_ARM_NEON) ++- if(HAVE_ARM_NEON) ++- set(SIMD_COMPILE_FLAGS "${SIMD_COMPILE_FLAGS} -mfpu=neon") +++ if(CMAKE_LIBRARY_ARCHITECTURE EQUAL "arm-linux-gnueabi") +++ set(SIMD_COMPILE_FLAGS "${SIMD_COMPILE_FLAGS} --with-arch=armv5te --with-float=soft") +++ else() +++ CHECK_C_COMPILER_FLAG(-mfpu=neon HAVE_ARM_NEON) +++ if(HAVE_ARM_NEON) +++ set(SIMD_COMPILE_FLAGS "${SIMD_COMPILE_FLAGS} -mfpu=neon") +++ endif() ++ endif() ++- ++ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i386|i686|amd64|x86_64|AMD64") ++ set(HAVE_INTEL 1) ++ if(CMAKE_SYSTEM_PROCESSOR MATCHES "i686|amd64|x86_64|AMD64") ++--- a/src/erasure-code/jerasure/gf-complete/m4/ax_ext.m4 +++++ b/src/erasure-code/jerasure/gf-complete/m4/ax_ext.m4 ++@@ -19,10 +19,17 @@ AC_DEFUN([AX_EXT], ++ ;; ++ ++ arm*) ++- AC_CACHE_CHECK([whether NEON is enabled], [ax_cv_have_neon_ext], [ax_cv_have_neon_ext=yes]) ++- if test "$ax_cv_have_neon_ext" = yes; then ++- AX_CHECK_COMPILE_FLAG(-mfpu=neon, [SIMD_FLAGS="$SIMD_FLAGS -mfpu=neon -DARM_NEON"], [ax_cv_have_neon_ext=no]) ++- fi +++ case $host_cpu in +++ arm-linux-gnueabi) +++ AX_CHECK_COMPILE_FLAG(-mfpu=soft, [SIMD_FLAGS="$SIMD_FLAGS -mfpu=soft -march=armv5te"], [ax_cv_have_neon_ext=no]) +++ ;; +++ *) +++ AC_CACHE_CHECK([whether NEON is enabled], [ax_cv_have_neon_ext], [ax_cv_have_neon_ext=yes]) +++ if test "$ax_cv_have_neon_ext" = yes; then +++ AX_CHECK_COMPILE_FLAG(-mfpu=neon, [SIMD_FLAGS="$SIMD_FLAGS -mfpu=neon -DARM_NEON"], [ax_cv_have_neon_ext=no]) +++ fi +++ ;; +++ esac ++ ;; ++ ++ powerpc*) diff --cc debian/patches/disable-crypto.patch index 000000000,000000000..b25aaac1b new file mode 100644 --- /dev/null +++ b/debian/patches/disable-crypto.patch @@@ -1,0 -1,0 +1,16 @@@ ++Index: ceph/src/os/CMakeLists.txt ++=================================================================== ++--- ceph.orig/src/os/CMakeLists.txt +++++ ceph/src/os/CMakeLists.txt ++@@ -98,8 +98,9 @@ endif() ++ target_link_libraries(os kv) ++ ++ add_dependencies(os compressor_plugins) ++-add_dependencies(os crypto_plugins) ++- +++if(HAVE_INTEL AND HAVE_BETTER_YASM_ELF64 AND (NOT APPLE)) +++ add_dependencies(os crypto_plugins) +++endif() ++ ++ if(WITH_BLUESTORE) ++ add_executable(ceph-bluestore-tool diff --cc debian/patches/disable-log-slow-requests.patch index 000000000,000000000..09d42911a new file mode 100644 --- /dev/null +++ b/debian/patches/disable-log-slow-requests.patch @@@ -1,0 -1,0 +1,38 @@@ ++From d6cd80e4efda43e9206aec46336a3d2ab21a0a36 Mon Sep 17 00:00:00 2001 ++From: Gerald Yang ++Date: Thu, 7 Jan 2021 03:04:02 +0000 ++Subject: [PATCH] Remove logging every slow request details to monitors ++ ++ recent change https://tracker.ceph.com/issues/43975 was made to slow ++ request logging to include detail on each operation in the cluster logs. ++ With this change, detail for every slow request is always sent to the ++ monitors and added to the cluster logs. ++ ++ This does not scale. Large, high-throughput clusters can overwhelm ++ their monitors with spurious logs in the event of a performance issue. ++ Disrupting the monitors can then cause further instability in the ++ cluster. ++ ++ This SRU reverts the cluster logging of every slow request the osd is ++ processing. ++ ++ The slow request clog change was added in nautilus (14.2.10) and ++ octopus (15.2.0). ++ ++Signed-off-by: Gerald Yang ++--- ++ src/osd/OSD.cc | 1 - ++ 1 file changed, 1 deletion(-) ++ ++Bug-Ubuntu: https://bugs.launchpad.net/bugs/1909162 ++ ++--- a/src/osd/OSD.cc +++++ b/src/osd/OSD.cc ++@@ -7758,7 +7758,6 @@ vector OSD::get_heal ++ << " currently " ++ << op.state_string(); ++ lgeneric_subdout(cct,osd,20) << ss.str() << dendl; ++- clog->warn() << ss.str(); ++ slow++; ++ if (!oldest_op || op.get_initiated() < oldest_op->get_initiated()) { ++ oldest_op = &op; diff --cc debian/patches/enable-strsignal.patch index 000000000,000000000..0cccbe920 new file mode 100644 --- /dev/null +++ b/debian/patches/enable-strsignal.patch @@@ -1,0 -1,0 +1,16 @@@ ++Description: This defines HAVE_REENTRANT_STRSIGNAL as sys_siglist no longer ++ exists with glibc 2.32 and all programs should use strsignal instead. ++Forwarded: no ++Last-Update: 2020-09-21 ++ ++--- a/CMakeLists.txt +++++ b/CMakeLists.txt ++@@ -501,7 +501,7 @@ if(WITH_THREAD_SAFE_RES_QUERY) ++ set(HAVE_THREAD_SAFE_RES_QUERY 1 CACHE INTERNAL "Thread safe res_query supported.") ++ endif() ++ ++-option(WITH_REENTRANT_STRSIGNAL "strsignal is reentrant" OFF) +++option(WITH_REENTRANT_STRSIGNAL "strsignal is reentrant" ON) ++ if(WITH_REENTRANT_STRSIGNAL) ++ set(HAVE_REENTRANT_STRSIGNAL 1 CACHE INTERNAL "Reentrant strsignal is supported.") ++ endif() diff --cc debian/patches/fix-bash-completion-location index 000000000,000000000..916ff8a79 new file mode 100644 --- /dev/null +++ b/debian/patches/fix-bash-completion-location @@@ -1,0 -1,0 +1,9 @@@ ++--- a/src/bash_completion/CMakeLists.txt +++++ b/src/bash_completion/CMakeLists.txt ++@@ -11,5 +11,5 @@ if(WITH_RADOSGW) ++ endif() ++ ++ install(FILES ${completions} ++- DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/bash_completion.d) +++ DESTINATION /usr/share/bash-completion/completions) ++ diff --cc debian/patches/fix-ceph-osd-systemd-target.patch index 000000000,000000000..9f42077ba new file mode 100644 --- /dev/null +++ b/debian/patches/fix-ceph-osd-systemd-target.patch @@@ -1,0 -1,0 +1,17 @@@ ++Description: Fix systemd ceph-osd.target ++ This helps when rebooting. ++Author: Thomas Goirand ++Forwarded: no ++Last-Update: 2021-01-28 ++ ++--- ceph-14.2.16.orig/systemd/ceph-osd.target +++++ ceph-14.2.16/systemd/ceph-osd.target ++@@ -1,7 +1,7 @@ ++ [Unit] ++ Description=ceph target allowing to start/stop all ceph-osd@.service instances at once ++ PartOf=ceph.target ++-After=ceph-mon.target +++After=ceph-mon.target systemd-udev-settle.service ++ Before=ceph.target ++ Wants=ceph.target ceph-mon.target ++ diff --cc debian/patches/only-yied-under-armv7-and-above.patch index 000000000,000000000..f5a9206b6 new file mode 100644 --- /dev/null +++ b/debian/patches/only-yied-under-armv7-and-above.patch @@@ -1,0 -1,0 +1,17 @@@ ++Description: Only yield under ARMv7 and above (#1176) ++Author: Rosen Penev ++Date: Tue, 12 Nov 2019 13:56:53 -0800 ++Origin: upstream, https://github.com/facebook/folly/commit/62d8e6e0b91ebd6f878f3066cd9b6e5f3c18a97b.patch ++Last-Update: 2021-11-24 ++ ++--- ceph-16.2.6+ds.orig/src/rocksdb/third-party/folly/folly/portability/Asm.h +++++ ceph-16.2.6+ds/src/rocksdb/third-party/folly/folly/portability/Asm.h ++@@ -19,7 +19,7 @@ inline void asm_volatile_pause() { ++ ::_mm_pause(); ++ #elif defined(__i386__) || FOLLY_X64 ++ asm volatile("pause"); ++-#elif FOLLY_AARCH64 || defined(__arm__) +++#elif FOLLY_AARCH64 || (defined(__arm__) && !(__ARM_ARCH < 7)) ++ asm volatile("yield"); ++ #elif FOLLY_PPC64 ++ asm volatile("or 27,27,27"); diff --cc debian/patches/riscv64-link-pthread.patch index 000000000,000000000..18b6eed93 new file mode 100644 --- /dev/null +++ b/debian/patches/riscv64-link-pthread.patch @@@ -1,0 -1,0 +1,16 @@@ ++Description: Link with -pthread instead of -lpthread to fix FTBFS on riscv64 ++Forwarded: no ++Last-Update: 2020-03-01 ++ ++Index: ceph/CMakeLists.txt ++=================================================================== ++--- ceph.orig/CMakeLists.txt +++++ ceph/CMakeLists.txt ++@@ -25,6 +25,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_S ++ ++ if(CMAKE_SYSTEM_NAME MATCHES "Linux") ++ set(LINUX ON) +++ set(THREADS_PREFER_PTHREAD_FLAG ON) ++ FIND_PACKAGE(Threads) ++ elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") ++ set(FREEBSD ON) diff --cc debian/patches/series index 000000000,000000000..5a9a776aa new file mode 100644 --- /dev/null +++ b/debian/patches/series @@@ -1,0 -1,0 +1,21 @@@ ++enable-strsignal.patch ++update-java-source-target-flags.patch ++disable-crypto.patch ++# Ubuntu: civetweb max connections ++civetweb-755-1.8-somaxconn-configurable_conf.patch ++civetweb-755-1.8-somaxconn-configurable.patch ++civetweb-755-1.8-somaxconn-configurable_test.patch ++# Upstream: py3 ++# Upstream: 32bit ++debian-armel-armhf-buildflags.patch ++fix-bash-completion-location ++32bit-fixes.patch ++add-option-to-disable-ceph-dencoder.patch ++riscv64-link-pthread.patch ++disable-log-slow-requests.patch ++fix-ceph-osd-systemd-target.patch ++compile-ppc.c-on-all-powerpc-machines.patch ++bug1914584.patch ++bug1917414.patch ++cmake-test-for-16-bytes-atomic-support-on-mips-also.patch ++only-yied-under-armv7-and-above.patch diff --cc debian/patches/update-java-source-target-flags.patch index 000000000,000000000..6c8b79228 new file mode 100644 --- /dev/null +++ b/debian/patches/update-java-source-target-flags.patch @@@ -1,0 -1,0 +1,23 @@@ ++Description: use --release 7 instead of -source/-target ++ Instead of -source/-target ceph should be build with --release for OpenJDK 9 ++ or later so that the bootclasspath is also set, as per JEP-247, otherwise it ++ risks incurring into binary incompatibility when run with an earlier OpenJDK. ++ OpenJDK 11 minimum compatibility release has been updated to 7. ++Author: Tiago Stürmer Daitx ++Bug-Ubuntu: https://launchpad.net/bugs/1756854 ++Bug-Ubuntu: https://launchpad.net/bugs/1766998 ++Forwarded: no ++Last-Update: 2018-04-24 ++--- ++ ++--- a/src/java/CMakeLists.txt +++++ b/src/java/CMakeLists.txt ++@@ -21,7 +21,7 @@ set(java_srcs ++ # warning: [options] bootstrap class path not set in conjunction with -source 1.7 ++ # as per ++ # https://blogs.oracle.com/darcy/entry/bootclasspath_older_source ++-set(CMAKE_JAVA_COMPILE_FLAGS "-source" "1.8" "-target" "1.8" "-Xlint:-options") +++set(CMAKE_JAVA_COMPILE_FLAGS "--release" "7" "-Xlint:-options") ++ set(jni_header_dir "${CMAKE_CURRENT_BINARY_DIR}/native") ++ if(CMAKE_VERSION VERSION_LESS 3.11) ++ set(CMAKE_JAVA_COMPILE_FLAGS ${CMAKE_JAVA_COMPILE_FLAGS} "-h" ${jni_header_dir}) diff --cc debian/py3dist-overrides index 000000000,000000000..c54eb2ebb new file mode 100644 --- /dev/null +++ b/debian/py3dist-overrides @@@ -1,0 -1,0 +1,1 @@@ ++ceph python3-ceph diff --cc debian/python3-ceph-argparse.install index 000000000,000000000..274b8b4f7 new file mode 100644 --- /dev/null +++ b/debian/python3-ceph-argparse.install @@@ -1,0 -1,0 +1,2 @@@ ++usr/lib/python3*/dist-packages/ceph_argparse.py ++usr/lib/python3*/dist-packages/ceph_daemon.py diff --cc debian/python3-ceph.lintian-overrides index 000000000,000000000..fd0d214b0 new file mode 100644 --- /dev/null +++ b/debian/python3-ceph.lintian-overrides @@@ -1,0 -1,0 +1,1 @@@ ++python3-ceph: empty-binary-package diff --cc debian/python3-cephfs.install index 000000000,000000000..6eb883670 new file mode 100644 --- /dev/null +++ b/debian/python3-cephfs.install @@@ -1,0 -1,0 +1,3 @@@ ++usr/lib/python3*/dist-packages/ceph_volume_client.py ++usr/lib/python3*/dist-packages/cephfs-*.egg-info ++usr/lib/python3*/dist-packages/cephfs.cpython*.so diff --cc debian/python3-rados.install index 000000000,000000000..98b5d76cb new file mode 100644 --- /dev/null +++ b/debian/python3-rados.install @@@ -1,0 -1,0 +1,2 @@@ ++usr/lib/python3*/dist-packages/rados-*.egg-info ++usr/lib/python3*/dist-packages/rados.cpython*.so diff --cc debian/python3-rbd.install index 000000000,000000000..5f4e6e143 new file mode 100644 --- /dev/null +++ b/debian/python3-rbd.install @@@ -1,0 -1,0 +1,2 @@@ ++usr/lib/python3*/dist-packages/rbd-*.egg-info ++usr/lib/python3*/dist-packages/rbd.cpython*.so diff --cc debian/python3-rgw.install index 000000000,000000000..57f455907 new file mode 100644 --- /dev/null +++ b/debian/python3-rgw.install @@@ -1,0 -1,0 +1,2 @@@ ++usr/lib/python3*/dist-packages/rgw-*.egg-info ++usr/lib/python3*/dist-packages/rgw.cpython*.so diff --cc debian/rados-objclass-dev.install index 000000000,000000000..ac8f90ee2 new file mode 100644 --- /dev/null +++ b/debian/rados-objclass-dev.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/include/rados/objclass.h diff --cc debian/radosgw.dirs index 000000000,000000000..a2f184912 new file mode 100644 --- /dev/null +++ b/debian/radosgw.dirs @@@ -1,0 -1,0 +1,1 @@@ ++var/lib/ceph/radosgw diff --cc debian/radosgw.install index 000000000,000000000..35805f5e4 new file mode 100644 --- /dev/null +++ b/debian/radosgw.install @@@ -1,0 -1,0 +1,9 @@@ ++lib/systemd/system/ceph-radosgw* ++usr/bin/radosgw ++usr/bin/radosgw-es ++usr/bin/radosgw-object-expirer ++usr/bin/radosgw-token ++usr/bin/rgw-gap-list ++usr/bin/rgw-gap-list-comparator ++usr/lib/*/libradosgw.so.* ++usr/share/man/man8/radosgw.8 diff --cc debian/radosgw.lintian-overrides index 000000000,000000000..5c5e06b8e new file mode 100644 --- /dev/null +++ b/debian/radosgw.lintian-overrides @@@ -1,0 -1,0 +1,8 @@@ ++# Ceph upstart configuration's don't have init.d equivalents ++radosgw: init.d-script-not-marked-as-conffile etc/init.d/radosgw-all-starter ++radosgw: init.d-script-not-included-in-package etc/init.d/radosgw-all-starter ++radosgw: init.d-script-not-marked-as-conffile etc/init.d/radosgw-instance ++radosgw: init.d-script-not-included-in-package etc/init.d/radosgw-instance ++radosgw: init.d-script-not-marked-as-conffile etc/init.d/radosgw-all ++radosgw: init.d-script-not-included-in-package etc/init.d/radosgw-all ++radosgw: omitted-systemd-service-for-init.d-script radosgw diff --cc debian/radosgw.postinst index 000000000,000000000..3f1551269 new file mode 100644 --- /dev/null +++ b/debian/radosgw.postinst @@@ -1,0 -1,0 +1,17 @@@ ++#!/bin/sh ++ ++set -e ++ ++if [ "${1}" = "configure" ] ; then ++ [ -f "/etc/default/ceph" ] && . /etc/default/ceph ++ [ -z "$SERVER_USER" ] && SERVER_USER=ceph ++ [ -z "$SERVER_GROUP" ] && SERVER_GROUP=ceph ++ if ! dpkg-statoverride --list /var/lib/ceph/radosgw >/dev/null; then ++ chown $SERVER_USER:$SERVER_GROUP /var/lib/ceph/radosgw ++ fi ++fi ++#DEBHELPER# ++ ++exit 0 ++ ++ diff --cc debian/radosgw.prerm index 000000000,000000000..0288ab77b new file mode 100644 --- /dev/null +++ b/debian/radosgw.prerm @@@ -1,0 -1,0 +1,22 @@@ ++#!/bin/sh ++# vim: set noet ts=8: ++ ++set -e ++ ++case "$1" in ++ remove) ++ invoke-rc.d radosgw stop || { ++ RESULT=$? ++ if [ $RESULT != 100 ]; then ++ exit $RESULT ++ fi ++ } ++ ;; ++ ++ *) ++ ;; ++esac ++ ++#DEBHELPER# ++ ++exit 0 diff --cc debian/rbd-fuse.install index 000000000,000000000..7b6b96fe7 new file mode 100644 --- /dev/null +++ b/debian/rbd-fuse.install @@@ -1,0 -1,0 +1,2 @@@ ++usr/bin/rbd-fuse ++usr/share/man/man8/rbd-fuse.8 diff --cc debian/rbd-mirror.install index 000000000,000000000..cc617a553 new file mode 100644 --- /dev/null +++ b/debian/rbd-mirror.install @@@ -1,0 -1,0 +1,3 @@@ ++lib/systemd/system/ceph-rbd-mirror* ++usr/bin/rbd-mirror ++usr/share/man/man8/rbd-mirror.8 diff --cc debian/rbd-nbd.install index 000000000,000000000..385c4501f new file mode 100644 --- /dev/null +++ b/debian/rbd-nbd.install @@@ -1,0 -1,0 +1,2 @@@ ++usr/bin/rbd-nbd ++usr/share/man/man8/rbd-nbd.8 diff --cc debian/rest-bench.install index 000000000,000000000..8535f20d5 new file mode 100644 --- /dev/null +++ b/debian/rest-bench.install @@@ -1,0 -1,0 +1,1 @@@ ++usr/bin/rest-bench diff --cc debian/rules index 000000000,000000000..dab17c06b new file mode 100755 --- /dev/null +++ b/debian/rules @@@ -1,0 -1,0 +1,236 @@@ ++#!/usr/bin/make -f ++# -*- makefile -*- ++#export DH_VERBOSE=1 ++export DESTDIR=$(CURDIR)/debian/tmp ++ ++DEB_HOST_ARCH_BITS ?= $(shell dpkg-architecture -qDEB_HOST_ARCH_BITS) ++export DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH) ++export DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH) ++ ++# support ccache for faster build ++# cmake uses /usr/bin/c* ++ifeq (yes,$(findstring yes,$(shell test -L /usr/lib/ccache/c++ && test -L /usr/lib/ccache/cc && echo -n yes))) ++ extraopts += -DWITH_CCACHE=ON ++endif ++ ++# try to save even more memory on some architectures ++# see #849657 for hints. ++# Reduce size of debug symbols to fix FTBFS due to the ++# 2GB/3GB address space limits on 32bit ++ifeq (32,$(DEB_HOST_ARCH_BITS)) ++export DEB_CFLAGS_MAINT_APPEND = -g1 -Os ++export DEB_CXXFLAGS_MAINT_APPEND = -g1 -Os ++endif ++ ++# we don't have NEON on armel. ++ifeq ($(DEB_HOST_ARCH),armel) ++ extraopts += -DHAVE_ARM_NEON=0 ++endif ++ ++# disable ceph-dencoder on 32bit except i386 to avoid g++ oom ++ifneq (,$(filter $(DEB_HOST_ARCH), armel armhf hppa m68k mips mipsel powerpc sh4 x32)) ++ extraopts += -DDISABLE_DENCODER=1 ++endif ++ ++ifeq ($(shell dpkg-vendor --is Ubuntu && echo yes) $(DEB_HOST_ARCH), yes i386) ++ skip_packages = -Nceph -Nceph-base -Nceph-mds -Nceph-mgr -Nceph-mon -Nceph-osd ++endif ++ ++# minimise needless linking and link to libatomic ++# The last is needed because long long atomic operations are not directly ++# supported by all processor architectures ++# The -Wl,--no-keep-memory should save memory but then will go slower. No choice, ++# as mipsel FTBFS. ++ifeq (32,$(DEB_HOST_ARCH_BITS)) ++export DEB_LDFLAGS_MAINT_APPEND= -Wl,--as-needed -latomic -Wl,--no-keep-memory ++endif ++ ++# Enable hardening ++export DEB_BUILD_MAINT_OPTIONS = hardening=+all optimize=-lto ++ ++export DESTDIR=$(CURDIR)/debian/tmp ++ ++export JAVA_HOME=/usr/lib/jvm/default-java ++## Set JAVAC to prevent FTBFS due to incorrect use of 'gcj' if found (see "m4/ac_prog_javac.m4"). ++export JAVAC=javac ++ ++extraopts += -DWITH_OCF=ON -DWITH_NSS=ON -DWITH_PYTHON3=ON -DWITH_DEBUG=ON ++extraopts += -DWITH_PYTHON2=OFF -DMGR_PYTHON_VERSION=3 ++extraopts += -DWITH_PYTHON3=3 ++extraopts += -DWITH_CEPHFS_JAVA=ON ++extraopts += -DWITH_CEPHFS_SHELL=ON ++extraopts += -DWITH_TESTS=OFF ++extraopts += -DWITH_SYSTEM_BOOST=ON ++extraopts += -DWITH_SYSTEM_LIBURING=ON ++extraopts += -DWITH_LTTNG=OFF -DWITH_EMBEDDED=OFF ++extraopts += -DCMAKE_INSTALL_LIBEXECDIR=/usr/lib ++extraopts += -DWITH_MGR_DASHBOARD_FRONTEND=OFF ++extraopts += -DWITH_SYSTEMD=ON -DCEPH_SYSTEMD_ENV_DIR=/etc/default ++extraopts += -DCMAKE_INSTALL_SYSCONFDIR=/etc ++extraopts += -DCMAKE_INSTALL_SYSTEMD_SERVICEDIR=/lib/systemd/system ++extraopts += -DWITH_RADOSGW_KAFKA_ENDPOINT=OFF ++extraopts += -DCMAKE_BUILD_TYPE=RelWithDebInfo ++extraopts += -DWITH_GRAFANA=ON ++extraopts += -DCMAKE_C_FLAGS_RELWITHDEBINFO="$(CFLAGS)" ++extraopts += -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="$(CXXFLAGS)" ++ ++ifneq (,$(findstring $(DEB_HOST_ARCH),amd64 arm64 ppc64el)) ++extraopts += -DWITH_RBD_RWL=ON ++extraopts += -DWITH_RBD_SSD_CACHE=ON ++extraopts += -DWITH_SYSTEM_PMDK=ON ++extraopts += -DWITH_BLUESTORE_PMEM=ON ++extraopts += -DWITH_SPDK=ON ++else ++# Disable SPDK as it generates a build which is no compatible ++# with older CPU's which are still supported by Ubuntu. ++extraopts += -DWITH_SPDK=OFF ++endif ++ ++# Enable crimson build on supported architectures ++ifneq (,$(findstring $(DEB_HOST_ARCH),amd64 arm64 ppc64el s390x)) ++extraopts += -DWITH_SEASTAR=ON -DSeastar_CXX_FLAGS=-DSEASTAR_DEFAULT_ALLOCATOR ++endif ++ ++ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) ++ NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) ++ extraopts += -DBOOST_J=$(NUMJOBS) ++endif ++ ++ifneq (,$(filter $(DEB_HOST_ARCH),ia64 m68k ppc64 sh4 sparc64 x32 alpha)) ++ # beast depends on libboost_{context,coroutine} which is not supported on s390x ++ extraopts += -DWITH_BOOST_CONTEXT=OFF ++else ++ extraopts += -DWITH_BOOST_CONTEXT=ON ++endif ++ ++# Disable SPDK as it generates a build which is no compatible ++# with older CPU's which are still supported by Ubuntu. ++extraopts += -DWITH_SPDK=OFF ++ ++MAX_PARALLEL ?= $(shell ./debian/calc-max-parallel.sh) ++ ++%: ++ dh $@ --buildsystem=cmake --with javahelper,python3 $(MAX_PARALLEL) ++ ++override_dh_auto_configure: ++ env | sort ++ dh_auto_configure --buildsystem=cmake -- $(extraopts) ++# after trying to patch the various places where HAVE_ARM_NEON is used ++# the easiest way to get rid of it on armel seems to be to patch the cmake ++# cache file. ++ifeq ($(DEB_HOST_ARCH),armel) ++ sed 's,^HAVE_ARM_NEON.*,HAVE_ARM_NEON:INTERNAL=0,' -i obj-arm-linux-gnueabi/CMakeCache.txt ++endif ++ ++override_dh_auto_install: ++ dh_auto_install --buildsystem=cmake --destdir=$(DESTDIR) ++ if [ ! -f $(DESTDIR)/usr/bin/ceph-dencoder ]; then \ ++ cp debian/workarounds/ceph-dencoder-oom $(DESTDIR)/usr/bin/ceph-dencoder ;\ ++ chmod 755 $(DESTDIR)/usr/bin/ceph-dencoder ;\ ++ fi ++ install -D -m 644 udev/50-rbd.rules $(DESTDIR)/lib/udev/rules.d/50-rbd.rules ++ install -D -m 644 src/etc-rbdmap $(DESTDIR)/etc/ceph/rbdmap ++ install -D -m 644 etc/sysctl/90-ceph-osd.conf $(DESTDIR)/etc/sysctl.d/30-ceph-osd.conf ++ install -D -m 600 sudoers.d/ceph-osd-smartctl $(DESTDIR)/etc/sudoers.d/ceph-osd-smartctl ++ install -D -m 755 src/tools/rbd_nbd/rbd-nbd_quiesce $(DESTDIR)/usr/libexec/rbd-nbd/rbd-nbd_quiesce ++ ++ install -m 755 src/cephadm/cephadm $(DESTDIR)/usr/sbin/cephadm ++ ++ install -m 644 -D monitoring/prometheus/alerts/ceph_default_alerts.yml $(DESTDIR)/etc/prometheus/ceph/ceph_default_alerts.yml ++ ++ # NOTE: ensure that any versioned erasure coding test code is dropped ++ # from the package install - package ships unversioned modules. ++ rm -f $(CURDIR)/debian/tmp/usr/lib/*/ceph/erasure-code/libec_*.so.* ++ find $(CURDIR)/debian/tmp/usr/lib/*/ceph/erasure-code -type l -delete || : ++ # avoid running out of disk space ++ rm -rf $(CURDIR)/obj-*-linux-gnu ++ ++# doc/changelog is a directory, which confuses dh_installchangelogs ++override_dh_installchangelogs: ++ dh_installchangelogs --exclude doc/changelog ++ ++override_dh_installlogrotate: ++ cp src/logrotate.conf debian/ceph-common.logrotate ++ dh_installlogrotate -pceph-common ++ ++override_dh_installinit: ++ cp src/init-radosgw debian/radosgw.init ++ dh_installinit --no-start ++ dh_installinit -pceph-common --name=rbdmap --no-start ++ dh_installinit -pceph-base --name ceph --no-start ++ # install the systemd stuff manually since we have funny service names ++ # and need to update the paths in all of the files post install ++ # systemd:ceph-common ++ install -d -m0755 debian/ceph-common/usr/lib/tmpfiles.d ++ install -m 0644 -D systemd/ceph.tmpfiles.d debian/ceph-common/usr/lib/tmpfiles.d/ceph.conf ++ # NOTE(jamespage): Install previous ceph-mon service from packaging for upgrades ++ install -d -m0755 debian/ceph-mon/lib/systemd/system ++ install -m0644 debian/lib-systemd/system/ceph-mon.service debian/ceph-mon/lib/systemd/system ++ ++override_dh_installsystemd: ++ # Ensure Debian/Ubuntu specific systemd units are NOT automatically enabled and started ++ # Enable systemd targets only ++ # Start systemd targets only ++ dh_installsystemd --no-stop-on-upgrade --no-restart-after-upgrade -Xceph-mon.service -Xceph-osd.service -X ceph-mds.service ++ ++override_dh_strip: ++ dh_strip -pceph-mds --dbg-package=ceph-mds-dbg ++ dh_strip -pceph-fuse --dbg-package=ceph-fuse-dbg ++ dh_strip -pceph-mgr --dbg-package=ceph-mgr-dbg ++ dh_strip -pceph-mon --dbg-package=ceph-mon-dbg ++ dh_strip -pceph-osd --dbg-package=ceph-osd-dbg ++ dh_strip -pceph-base --dbg-package=ceph-base-dbg ++ dh_strip -pcephfs-mirror --dbg-package=cephfs-mirror-dbg ++ dh_strip -prbd-fuse --dbg-package=rbd-fuse-dbg ++ dh_strip -prbd-mirror --dbg-package=rbd-mirror-dbg ++ dh_strip -pceph-immutable-object-cache --dbg-package=ceph-immutable-object-cache-dbg ++ dh_strip -prbd-nbd --dbg-package=rbd-nbd-dbg ++ dh_strip -pceph-common --dbg-package=ceph-common-dbg ++ dh_strip -plibrados2 --dbg-package=librados2-dbg ++ dh_strip -plibsqlite3-mod-ceph --dbg-package=libsqlite3-mod-ceph-dbg ++ dh_strip -plibradosstriper1 --dbg-package=libradosstriper1-dbg ++ dh_strip -plibrbd1 --dbg-package=librbd1-dbg ++ dh_strip -plibcephfs2 --dbg-package=libcephfs2-dbg ++ dh_strip -plibrgw2 --dbg-package=librgw2-dbg ++ dh_strip -pradosgw --dbg-package=radosgw-dbg ++ dh_strip -pceph-test ++ ++ # No -dbg packages for python3 bindings. ++ dh_strip -ppython3-cephfs ++ dh_strip -ppython3-rados ++ dh_strip -ppython3-rbd ++ dh_strip -ppython3-rgw ++ ++ dh_strip -plibcephfs-jni ++ dh_strip -plibrados-dev ++ ++override_dh_makeshlibs: ++ # exclude jni libraries in libcephfs-jni to avoid pointless ldconfig ++ # calls in maintainer scripts; exclude private erasure-code plugins. ++ dh_makeshlibs -V -X/usr/lib/jni -X/usr/lib/$(DEB_HOST_MULTIARCH)/ceph/erasure-code ++ ++override_dh_auto_test: ++ # do not run tests ++ ++override_dh_shlibdeps: ++ dh_shlibdeps -a --exclude=erasure-code --exclude=rados-classes --exclude=compressor ++ ++override_dh_python3: ++ for binding in ceph ceph-argparse cephfs rados rbd rgw; do \ ++ dh_python3 -p python3-$$binding --shebang=/usr/bin/python3; \ ++ done ++ dh_python3 -p python3-ceph-argparse --shebang=/usr/bin/python3 ++ dh_python3 -p ceph-common --shebang=/usr/bin/python3 ++ dh_python3 -p ceph-base --shebang=/usr/bin/python3 ++ dh_python3 -p ceph-osd --shebang=/usr/bin/python3 ++ dh_python3 -p ceph-mgr --shebang=/usr/bin/python3 ++ dh_python3 -p cephfs-shell --shebang=/usr/bin/python3 ++ dh_python3 -p cephfs-top --shebang=/usr/bin/python3 ++ dh_python3 -p cephadm --shebang=/usr/bin/python3 ++ ++override_dh_builddeb: ++ dh_builddeb ${skip_packages} ++ ++override_dh_gencontrol: ++ dh_gencontrol ${skip_packages} ++ diff --cc debian/source.lintian-overrides index 000000000,000000000..6a4dc1a74 new file mode 100644 --- /dev/null +++ b/debian/source.lintian-overrides @@@ -1,0 -1,0 +1,3 @@@ ++# This is a false positive: upstream is shipping both the compiled ++# and the source version of the .js files. ++ceph source: source-is-missing diff --cc debian/source/format index 000000000,000000000..163aaf8d8 new file mode 100644 --- /dev/null +++ b/debian/source/format @@@ -1,0 -1,0 +1,1 @@@ ++3.0 (quilt) diff --cc debian/source/lintian-overrides index 000000000,000000000..f3cb221b9 new file mode 100644 --- /dev/null +++ b/debian/source/lintian-overrides @@@ -1,0 -1,0 +1,11 @@@ ++# we don't ship thse thirdparty libs here, afaics. ++# license.txt is outdated but fixing it causes the same error ++# come up for the patch, so... ++ceph source: license-problem-json-evil src/rapidjson/license.txt ++ ++# pybind js source is in src/pybind/mgr/dashboard/frontend/src ++ceph source: source-is-missing src/pybind/mgr/dashboard/frontend/dist/*.js ++ ++# regression test file is actually shipped with source and build files ++ceph source: source-contains-prebuilt-ms-help-file src/boost/tools/boost_install/test/iostreams/zlib-1.2.11/contrib/dotzlib/DotZLib.chm ++ceph source: source-contains-prebuilt-ms-help-file src/boost/libs/beast/test/extern/zlib-1.2.11/contrib/dotzlib/DotZLib.chm diff --cc debian/source/options index 000000000,000000000..d029bb02e new file mode 100644 --- /dev/null +++ b/debian/source/options @@@ -1,0 -1,0 +1,11 @@@ ++extend-diff-ignore = ".*src/rapidjson/thirdparty/gtest/googlemock/msvc/20\d\d/gmock\.sln" ++extend-diff-ignore = ".*src/rapidjson/thirdparty/gtest/googlemock/msvc/20\d\d/gmock.*vcproj" ++extend-diff-ignore = ".*src/rapidjson/thirdparty/gtest/googlemock/msvc/20\d\d/gmock.*vsprops" ++extend-diff-ignore = ".*src/rapidjson/thirdparty/gtest/googlemock/msvc/20\d\d/gmock.*vcxproj" ++extend-diff-ignore = ".*src/rapidjson/thirdparty/gtest/googlemock/msvc/20\d\d/gmock_config.props" ++extend-diff-ignore = ".*src/rapidjson/thirdparty/gtest/googletest/codegear/gtest.*\.cbproj" ++extend-diff-ignore = ".*src/rapidjson/thirdparty/gtest/googletest/codegear/gtest_all\.cc" ++extend-diff-ignore = ".*src/rapidjson/thirdparty/gtest/googletest/codegear/gtest_link\.cc" ++extend-diff-ignore = ".*src/rapidjson/thirdparty/gtest/googletest/codegear/gtest\.groupproj" ++extend-diff-ignore = ".*src/rapidjson/thirdparty/gtest/googletest/msvc/gtest.*\.vcproj" ++extend-diff-ignore = ".*src/rapidjson/thirdparty/gtest/googletest/msvc/gtest.*\.sln" diff --cc debian/tests/build-rados index 000000000,000000000..c62999251 new file mode 100755 --- /dev/null +++ b/debian/tests/build-rados @@@ -1,0 -1,0 +1,31 @@@ ++#!/bin/sh ++# autopkgtest check: Build and run a program against librados2 to ++# validate that headers are installed and libraries exists ++ ++set -e ++ ++WORKDIR=$(mktemp -d) ++trap "rm -rf $WORKDIR" 0 INT QUIT ABRT PIPE TERM ++cd $WORKDIR ++cat < radostest.c ++#include ++ ++int ++main(void) ++{ ++ int err; ++ rados_t cluster; ++ ++ err = rados_create(&cluster, NULL); ++ if (err < 0) { ++ return (1); ++ } ++ return(0); ++} ++EOF ++ ++gcc -o radostest radostest.c -lrados ++echo "build: OK" ++[ -x radostest ] ++./radostest ++echo "run: OK" diff --cc debian/tests/build-rbd index 000000000,000000000..5ad6f8823 new file mode 100755 --- /dev/null +++ b/debian/tests/build-rbd @@@ -1,0 -1,0 +1,24 @@@ ++#!/bin/sh ++# autopkgtest check: Build and run a program against librbd1 to ++# validate that headers are installed and libraries exists ++ ++set -e ++ ++WORKDIR=$(mktemp -d) ++trap "rm -rf $WORKDIR" 0 INT QUIT ABRT PIPE TERM ++cd $WORKDIR ++cat < rbdtest.c ++#include ++ ++int ++main(void) ++{ ++ return(0); ++} ++EOF ++ ++gcc -o rbdtest rbdtest.c -lrbd ++echo "build: OK" ++[ -x rbdtest ] ++./rbdtest ++echo "run: OK" diff --cc debian/tests/ceph-client index 000000000,000000000..c693a5698 new file mode 100755 --- /dev/null +++ b/debian/tests/ceph-client @@@ -1,0 -1,0 +1,11 @@@ ++#!/bin/bash ++ ++set -e ++ ++CLIENTS=('ceph') ++ ++for client in "${CLIENTS[@]}"; do ++ echo -n "Testing client $client: " ++ $client -v 2>&1 > /dev/null ++ echo "OK" ++done diff --cc debian/tests/control index 000000000,000000000..372a057d0 new file mode 100644 --- /dev/null +++ b/debian/tests/control @@@ -1,0 -1,0 +1,9 @@@ ++Tests: ceph-client build-rados build-rbd python-ceph ++Depends: ++ build-essential, ++ ceph-common, ++ librados-dev, ++ librbd-dev, ++ python3-rados, ++ python3-rbd, ++Restrictions: needs-root diff --cc debian/tests/python-ceph index 000000000,000000000..006dbe63d new file mode 100755 --- /dev/null +++ b/debian/tests/python-ceph @@@ -1,0 -1,0 +1,7 @@@ ++#!/usr/bin/python3 ++ ++# Test that rbd and rados can be imported OK ++import rbd ++import rados ++ ++print("python-ceph: OK") diff --cc debian/udev/95-ceph-osd-lvm.rules index 000000000,000000000..00feae51f new file mode 100644 --- /dev/null +++ b/debian/udev/95-ceph-osd-lvm.rules @@@ -1,0 -1,0 +1,13 @@@ ++# OSD LVM layout example ++# VG prefix: ceph- ++# LV prefix: osd- ++ACTION=="add", SUBSYSTEM=="block", \ ++ ENV{DEVTYPE}=="disk", \ ++ ENV{DM_LV_NAME}=="osd-*", \ ++ ENV{DM_VG_NAME}=="ceph-*", \ ++ OWNER:="ceph", GROUP:="ceph", MODE:="660" ++ACTION=="change", SUBSYSTEM=="block", \ ++ ENV{DEVTYPE}=="disk", \ ++ ENV{DM_LV_NAME}=="osd-*", \ ++ ENV{DM_VG_NAME}=="ceph-*", \ ++ OWNER="ceph", GROUP="ceph", MODE="660" diff --cc debian/watch index 000000000,000000000..899ddb7d7 new file mode 100644 --- /dev/null +++ b/debian/watch @@@ -1,0 -1,0 +1,6 @@@ ++version=3 ++opts=repacksuffix=+ds,\ ++repack,compression=xz,\ ++uversionmangle=s/-/~/,\ ++dversionmangle=s/\+(debian|dfsg|ds|deb)(\.\d+)?$// \ ++ http://download.ceph.com/tarballs/ceph-(\d.*)\.tar\.gz diff --cc debian/workarounds/ceph-dencoder-oom index 000000000,000000000..872021328 new file mode 100644 --- /dev/null +++ b/debian/workarounds/ceph-dencoder-oom @@@ -1,0 -1,0 +1,7 @@@ ++#!/bin/bash ++ ++echo "Unfortunately it is not possible to compile ceph-dencoder" 1>&2 ++echo "on this architecture, see bug #947886." 1>&2 ++echo "" 1>&2 ++exit 1 ++