solvespace (3.1+ds1-3.1) unstable; urgency=medium
authorBenjamin Drung <bdrung@debian.org>
Thu, 29 Feb 2024 17:02:12 +0000 (17:02 +0000)
committerBenjamin Drung <bdrung@debian.org>
Thu, 29 Feb 2024 17:02:12 +0000 (17:02 +0000)
  * Non-maintainer upload.
  * Rename libraries for 64-bit time_t transition.  Closes: #1062911

[dgit import unpatched solvespace 3.1+ds1-3.1]

34 files changed:
1  2 
debian/.gitlab-ci.yml
debian/changelog
debian/control
debian/copyright
debian/docs
debian/libslvs1-dev.install
debian/libslvs1t64.install
debian/libslvs1t64.lintian-overrides
debian/missing_sources/res/threejs/hammer-2.0.8.js
debian/patches/01_hardcode_git_hash.patch
debian/patches/02_add_debian_pkg_version.patch
debian/patches/03_use_system_threejs.patch
debian/patches/04_use_system_unifont.patch
debian/patches/series
debian/rules
debian/solvespace-cli.1
debian/solvespace.1
debian/solvespace.install
debian/solvespace.links
debian/solvespace.lintian-overrides
debian/solvespace.manpages
debian/solvespace.sharedmimeinfo
debian/source/format
debian/source/options
debian/tests/common
debian/tests/control
debian/tests/htmlmesh
debian/tests/stlmesh
debian/tests/surfaces
debian/tests/thumbnail
debian/tests/view
debian/tests/wireframe
debian/upstream/metadata
debian/watch

index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b9b8b887098831a9f780157eee603f836f766b51
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++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
++
++reprotest:
++  allow_failure: true
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ba0c9ca2c200ae081fe42b815bb8d4ddd4572db1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,204 @@@
++solvespace (3.1+ds1-3.1) unstable; urgency=medium
++
++  * Non-maintainer upload.
++  * Rename libraries for 64-bit time_t transition.  Closes: #1062911
++
++ -- Benjamin Drung <bdrung@debian.org>  Thu, 29 Feb 2024 17:02:12 +0000
++
++solvespace (3.1+ds1-3) unstable; urgency=medium
++
++  * Team upload.
++  * Restore architectures, and just exclude s390x from affected tests.
++    Thanks to Graham Inggs. Closes: #1025311
++
++ -- Ryan Pavlik <ryan@ryanpavlik.com>  Wed, 07 Dec 2022 16:25:41 -0600
++
++solvespace (3.1+ds1-2) unstable; urgency=medium
++
++  * Team upload.
++  * Drop s390x architecture due to test failures. Closes: #1013163
++  * Bump Standards-Version to 4.6.1. No changes required.
++  * d/copyright: Update
++  * Update lintian overrides.
++
++ -- Ryan Pavlik <ryan@ryanpavlik.com>  Mon, 19 Sep 2022 12:49:06 -0500
++
++solvespace (3.1+ds1-1) unstable; urgency=medium
++
++  * Team upload.
++  * New upstream version 3.1+ds1
++  * Rediff patches.
++    Drop 05_eigen_dependency_fix.patch: Applied upstream.
++    Drop 06_desktop_file_exec.patch: Applied upstream.
++
++ -- Ryan Pavlik <ryan@ryanpavlik.com>  Mon, 11 Jul 2022 08:55:26 -0500
++
++solvespace (3.1~rc1+ds1-1) unstable; urgency=medium
++
++  * New upstream version 3.1~rc1+ds1. Closes: #983952
++  * d/watch: Update to get new pattern for tarballs with submodules
++  * d/control:
++    - Add Build-Depends.
++    - Remove libjs-three and unifont from Build-Depends, only
++      needed at runtime for the GUI
++  * d/copyright: Exclude vendored files available in Debian, binaries,
++    minified Javascript, prebuilt docs
++  * d/solvespace.lintian-overrides: Add overrides for false positives
++  * d/get_orig.sh: Remove, no longer needed, uscan works now.
++  * d/patches:
++    - Drop 10_mimalloc_restrict_cpu_yield.patch: applied upstream.
++    - Drop 11_update_js_three_r111.patch: applied upstream.
++    - Drop 12_Remove-march-native-from-mimalloc-build.patch: applied upstream.
++    - Revise 01_RemoveGitHash.patch into 01_hardcode_git_hash.patch: Hash
++      needed to create commit link in app now.
++    - Add 05_eigen_dependency_fix.patch: Fix test suite build.
++    - Add 06_desktop_file_exec.patch: Fix desktop file lintian warning.
++
++ -- Ryan Pavlik <ryan@ryanpavlik.com>  Thu, 19 May 2022 16:05:37 -0500
++
++solvespace (3.0.rc2+repack1-3) unstable; urgency=medium
++
++  * Add 12_Remove-march-native-from-mimalloc-build.patch:
++    fix buildd-discovered issue.
++  * Update patch metadata.
++
++ -- Ryan Pavlik <ryan@ryanpavlik.com>  Thu, 11 Feb 2021 15:06:33 -0600
++
++solvespace (3.0.rc2+repack1-2) unstable; urgency=medium
++
++  * Upload into unstable
++
++ -- Anton Gladky <gladk@debian.org>  Sat, 06 Feb 2021 20:04:57 +0100
++
++solvespace (3.0.rc2+repack1-2~exp1) experimental; urgency=medium
++
++  * Team upload.
++  [ Ryan Pavlik ]
++  * Enable LTO and OpenMP in build system
++
++  [ Michael R. Crusoe ]
++  * Remove erroneously added debian/salsa-ci.yml.
++
++ -- Michael R. Crusoe <crusoe@debian.org>  Sat, 23 Jan 2021 20:31:05 +0100
++
++solvespace (3.0.rc2+repack1-1) unstable; urgency=medium
++
++  * Team upload.
++
++  [ Ryan Pavlik ]
++  * New upstream version 3.0.rc2+repack1
++  * Adjust get_orig.sh script for RC2
++  * d/rules: Specify package version for CMake.
++  * Drop 20_use_system_flatbuffers: Upstream dep removed.
++  * Add 02_add_debian_pkg_version.patch to provide better
++    version ID to upstream
++  * Add 03_use_system_threejs.patch, update d/control to use
++    system-provided three.js
++  * Add 04_use_system_unifont.patch, update d/control to use
++    system unifont
++  * Add 10_mimalloc_restrict_cpu_yield.patch to fix mimalloc
++    armel build.
++  * Add 11_update_js_three_r111.patch to support three.js r111
++    as found in unstable, instead of old r76 bundled in tree.
++  * d/control
++    - Fix warning about substitution variable
++    - Update description to cover new operations
++    - Update version in Build-Depends for CMake
++    - Remove Build-Depends on libflatbuffers-dev.
++  * Add missing_sources for hammer js
++  * Update copyright file
++  * Package more docs
++  * Add manpage for solvespace-cli from notesalexp repo.
++  * Update solvespace manpage
++  * Ensure build flags are exported and used
++  * Add autopkgtests
++
++  [ Michael R. Crusoe ]
++  * Do not parse d/changelog (routine-update)
++  * Add salsa-ci file (routine-update)
++  * debian/upstream/metadata: mention upstream's GitHub repository
++  * debian/patches/03_use_system_threejs.patch: refreshed
++  * debian/patches/10_mimalloc_restrict_cpu_yield.patch: enhanced with better
++    atomic yield for SSE2 (if available) and better/added ops for arm64,
++    armel, and ppc64{el,}/powerpc. Closes: #980169
++  * Run the build-time tests as part of the build on amd64.
++
++ -- Michael R. Crusoe <crusoe@debian.org>  Sat, 23 Jan 2021 20:15:11 +0100
++
++solvespace (3.0.rc1+repack1-4) unstable; urgency=medium
++
++  * [3fa5dd1] Remove arm-patch
++
++ -- Anton Gladky <gladk@debian.org>  Fri, 15 Jan 2021 15:40:02 +0100
++
++solvespace (3.0.rc1+repack1-3) unstable; urgency=medium
++
++  * [fa2ba63] Use CXX for mimalloc compilation
++
++ -- Anton Gladky <gladk@debian.org>  Thu, 14 Jan 2021 23:41:14 +0100
++
++solvespace (3.0.rc1+repack1-2) unstable; urgency=medium
++
++  * [7192813] Update d/copyright
++  * [93f958e] Fix compilation on armel
++
++ -- Anton Gladky <gladk@debian.org>  Thu, 14 Jan 2021 19:41:26 +0100
++
++solvespace (3.0.rc1+repack1-1) unstable; urgency=medium
++
++  * [2c974c1] New upstream version 3.0.rc1+repack1
++  * [d29ee68] Update get_orig script
++  * [73cbc23] Refresh patches
++  * [d8e0c6c] Use gtk3. (Closes: #967751)
++  * [09453c9] Update watch file format version to 4.
++  * [70475f7] Set Standards-Version to 4.5.1
++
++ -- Anton Gladky <gladk@debian.org>  Tue, 12 Jan 2021 23:27:41 +0100
++
++solvespace (2.3+repack1-4) unstable; urgency=medium
++
++  * [f5f8b5c] Add link to the fixed by upstream issue
++  * [4ac4b71] Use secure URI in Homepage field.
++  * [ef3f5da] Bump debhelper from old 10 to 13.
++  * [047d9c4] Set debhelper-compat version in Build-Depends.
++  * [8b28a26] Set upstream metadata fields: Bug-Database, Bug-Submit.
++  * [fba85d0] Update Vcs-* headers from URL redirect.
++  * [ab740f9] Use canonical URL in Vcs-Git.
++  * [84a98ae] Replace libglu-dev by libglu1-mesa-dev in BD
++  * [fdf3c0d] Set Standards-version to 4.5.0. No changes
++  * [cefcb01] Set Rules-Requires-Root: no
++  * [9869a0d] Add .gitlab-ci.yml
++  * [53ab556] Install usr/share/pixmaps
++
++ -- Anton Gladky <gladk@debian.org>  Mon, 01 Jun 2020 22:17:17 +0200
++
++solvespace (2.3+repack1-3) unstable; urgency=medium
++
++  * [6d84f29] Set minimal cmake version to 3.1.0.
++  * [be690c9] Fix FTBFS with glibc 2.25. (Closes: #882167)
++  * [6c8697c] Set Standards-Version: 4.1.1
++  * [2c3d9bd] Set compat level 10
++  * [fb232b5] Set maximal hardening options
++
++ -- Anton Gladky <gladk@debian.org>  Wed, 22 Nov 2017 09:54:12 +0100
++
++solvespace (2.3+repack1-2) unstable; urgency=medium
++
++  * [0d4dc2b] Add missing dependency on libslvs1. (Closes: #856937)
++
++ -- Anton Gladky <gladk@debian.org>  Mon, 06 Mar 2017 20:59:20 +0100
++
++solvespace (2.3+repack1-1) unstable; urgency=medium
++
++  * [a7825d4] Add d/watch.
++  * [15facd8] Update get_orig.sh script.
++  * [4bcf775] New upstream version 2.3+repack1
++  * [5bfcd9a] Refresh patch.
++
++ -- Anton Gladky <gladk@debian.org>  Sat, 31 Dec 2016 09:54:59 +0100
++
++solvespace (2.1+repack2-1) unstable; urgency=medium
++
++  * Initial Release. (Closes: #797997)
++
++ -- Anton Gladky <gladk@debian.org>  Mon, 15 Aug 2016 22:31:44 +0200
diff --cc debian/control
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9ea5afc50064024da240169251b5c5c38ea3d7f7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,74 @@@
++Source: solvespace
++Maintainer: Debian Science Maintainers <debian-science-maintainers@lists.alioth.debian.org>
++Uploaders: whitequark <whitequark@whitequark.org>,
++           Anton Gladky <gladk@debian.org>
++Section: graphics
++Priority: optional
++Build-Depends: dpkg-dev (>= 1.22.5), cmake (>= 3.9),
++               debhelper-compat (= 13),
++               libeigen3-dev,
++               libfontconfig1-dev,
++               libfreetype-dev,
++               libgl-dev,
++               libglew-dev,
++               libglu1-mesa-dev,
++               libgtkmm-3.0-dev,
++               libjson-c-dev,
++               libpangomm-1.4-dev,
++               libpng-dev,
++               libspnav-dev,
++               zlib1g-dev
++Standards-Version: 4.6.1
++Vcs-Browser: https://salsa.debian.org/science-team/solvespace
++Vcs-Git: https://salsa.debian.org/science-team/solvespace.git
++Homepage: https://solvespace.com
++Rules-Requires-Root: no
++
++Package: solvespace
++Architecture: any
++Multi-Arch: foreign
++Depends: ${misc:Depends},
++         ${shlibs:Depends},
++         libjs-three,
++         unifont
++Description: Parametric 2d/3d CAD
++ SolveSpace is a parametric 2d/3d CAD program. Applications include:
++ .
++  * modeling 3d parts — draw with extrudes, revolves, helix creation,
++    and Boolean (union / difference / intersection) operations;
++  * modeling 2d parts — draw the part as a single section, and export DXF,
++    PDF, SVG; use 3d assembly to verify fit;
++  * 3d-printed parts — export the STL or other triangle mesh expected by
++    most 3d printers;
++  * preparing CAM data — export 2d vector art for a waterjet machine or
++    laser cutter; or generate STEP or STL, for import into third-party
++    CAM software for machining;
++  * mechanism design — use the constraint solver to simulate planar or
++    spatial linkages, with pin, ball, or slide joints;
++  * plane and solid geometry — replace hand-solved trigonometry and
++    spreadsheets with a live dimensioned drawing.
++
++Package: libslvs1t64
++Provides: ${t64:Provides}
++Replaces: libslvs1
++Breaks: libslvs1 (<< ${source:Version})
++Architecture: any
++Multi-Arch: same
++Section: libs
++Depends: ${misc:Depends},
++         ${shlibs:Depends}
++Description: SolveSpace geometric kernel
++ SolveSpace is a parametric 2d/3d CAD. libslvs contains the geometric
++ kernel of SolveSpace, built as a library.
++
++Package: libslvs1-dev
++Architecture: any
++Multi-Arch: same
++Section: libdevel
++Depends: ${misc:Depends},
++         libslvs1t64 (= ${binary:Version})
++Description: SolveSpace geometric kernel (development files)
++ SolveSpace is a parametric 2d/3d CAD. libslvs contains the geometric
++ kernel of SolveSpace, built as a library.
++ .
++ This package includes development files for libslvs.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b9727b2954ab78e69031797a415534e85a28c6e3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,267 @@@
++Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
++Upstream-Name: solvespace
++Source: https://github.com/solvespace/solvespace
++Comment: Excluding vendored third-party libs available in Debian,
++  minified javascript, vendored unifot,  Windows-only binaries, and
++  prebuilt documentation
++Files-Excluded:
++  extlib/angle
++  extlib/cairo
++  extlib/eigen
++  extlib/freetype
++  extlib/libpng
++  extlib/mimalloc/bin
++  extlib/mimalloc/docs
++  extlib/pixman
++  extlib/si
++  extlib/zlib
++  res/fonts/unifont.hex.gz
++  res/threejs/three-*
++
++Files: *
++Copyright: 2008-2022, Jonathan Westhues and other authors
++  2015-2020, whitequark <whitequark@whitequark.org>
++  2015, 2016, Aleksey Egorov <anandamide@mail.ru>
++License: GPL-3.0+
++
++Files: cmake/*
++Copyright: 2008-2020, Jonathan Westhues and other authors
++License: GPL-3.0+
++
++Files: debian/*
++Copyright: 2021-2022, Ryan Pavlik <ryan@ryanpavlik.com>
++  2016, 2017, 2020, 2021, Anton Gladky <gladk@debian.org>
++  2015, 2016, whitequark <whitequark@whitequark.org>
++License: GPL-3.0+
++
++Files: debian/solvespace-cli.1
++Copyright: 2016 Alexander Pozdnyakov <almipo@mail.ru>
++License: GPL-3.0+
++
++Files: debian/missing_sources/res/threejs/hammer-2.0.8.js
++  res/threejs/hammer-2.0.8.js.gz
++Copyright: 2016, Jorik Tangelder
++License: Expat
++
++Files: extlib/libdxfrw/*
++Copyright: 2011-2015, José F. Soriano (Rallaz) <rallazz@gmail.com>
++License: GPL-2.0+
++
++Files: extlib/mimalloc/*
++Copyright: 2018-2021, Microsoft Research
++  2019, Daan Leijen
++License: Expat
++
++Files: src/importidf.cpp
++Copyright: 2020, Paul Kahler.
++License: GPL-3.0+
++
++Files: src/polyline.cpp
++Copyright: 2016, M-Labs Ltd
++License: GPL-3.0+
++
++Files: src/ttf.cpp
++  src/ttf.h
++Copyright: 2016, whitequark, Peter Barfuss.
++License: GPL-3.0+
++
++Files: res/fonts/unicode.lff.gz
++Copyright: 2011-2012, José F. Soriano <rallazz@gmail.com>
++ 2011, Eugene Osintsev <osgene@omskelecom.ru>
++ 2002, Yoshimune Kobayashi <cfg47520@syd.odn.ne.jp>
++License: GPL-2.0+
++Comment: From LibreCAD, referenced explicitly by path.
++
++Files: test/Gentium-R.ttf
++Copyright: 2003-2011, SIL International
++License: OFL-1.1-RFN
++Comment: Reserved Font Names "Gentium" and "SIL". Used for test cases.
++
++Files: res/fonts/BitstreamVeraSans-Roman-builtin.ttf
++Copyright: 2003, Bitstream, Inc.
++License: other
++ Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a
++ trademark of Bitstream, Inc.
++ .
++ Permission is hereby granted, free of charge, to any person obtaining a copy of
++ the fonts accompanying this license (“Fonts”) and associated documentation files
++ (the “Font Software”), to reproduce and distribute the Font Software, including
++ without limitation the rights to use, copy, merge, publish, distribute, and/or
++ sell copies of the Font Software, and to permit persons to whom the Font
++ Software is furnished to do so, subject to the following conditions:
++ .
++ The above copyright and trademark notices and this permission notice shall be
++ included in all copies of one or more of the Font Software typefaces.
++ .
++ The Font Software may be modified, altered, or added to, and in particular the
++ designs of glyphs or characters in the Fonts may be modified and additional
++ glyphs or characters may be added to the Fonts, only if the fonts are renamed to
++ names not containing either the words “Bitstream” or the word “Vera”.
++ .
++ This License becomes null and void to the extent applicable to Fonts or Font
++ Software that has been modified and is distributed under the “Bitstream Vera”
++ names.
++ .
++ The Font Software may be sold as part of a larger software package but no copy
++ of one or more of the Font Software typefaces may be sold by itself.
++ .
++ THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS
++ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR
++ OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR
++ ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT,
++ INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
++ OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR
++ FROM OTHER DEALINGS IN THE FONT SOFTWARE.
++ .
++ Except as contained in this notice, the names of GNOME, the GNOME Foundation,
++ and Bitstream Inc., shall not be used in advertising or otherwise to promote the
++ sale, use or other dealings in this Font Software without prior written
++ authorization from the GNOME Foundation or Bitstream Inc., respectively. For
++ further information, contact: fonts at gnome dot org.
++
++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.
++
++License: GPL-2.0+
++ 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 <http://www.gnu.org/licenses/>.
++ .
++ 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.0+
++ 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 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 <http://www.gnu.org/licenses/>.
++ .
++ 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: OFL-1.1-RFN
++ This Font Software is licensed under the SIL Open Font License, Version 1.1.
++ This license is copied below, and is also available with a FAQ at:
++ http://scripts.sil.org/OFL
++ .
++ .
++ -----------------------------------------------------------
++ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
++ -----------------------------------------------------------
++ .
++ PREAMBLE
++ The goals of the Open Font License (OFL) are to stimulate worldwide
++ development of collaborative font projects, to support the font creation
++ efforts of academic and linguistic communities, and to provide a free and
++ open framework in which fonts may be shared and improved in partnership
++ with others.
++ .
++ The OFL allows the licensed fonts to be used, studied, modified and
++ redistributed freely as long as they are not sold by themselves. The
++ fonts, including any derivative works, can be bundled, embedded,
++ redistributed and/or sold with any software provided that any reserved
++ names are not used by derivative works. The fonts and derivatives,
++ however, cannot be released under any other type of license. The
++ requirement for fonts to remain under this license does not apply
++ to any document created using the fonts or their derivatives.
++ .
++ DEFINITIONS
++ "Font Software" refers to the set of files released by the Copyright
++ Holder(s) under this license and clearly marked as such. This may
++ include source files, build scripts and documentation.
++ .
++ "Reserved Font Name" refers to any names specified as such after the
++ copyright statement(s).
++ .
++ "Original Version" refers to the collection of Font Software components as
++ distributed by the Copyright Holder(s).
++ .
++ "Modified Version" refers to any derivative made by adding to, deleting,
++ or substituting -- in part or in whole -- any of the components of the
++ Original Version, by changing formats or by porting the Font Software to a
++ new environment.
++ .
++ "Author" refers to any designer, engineer, programmer, technical
++ writer or other person who contributed to the Font Software.
++ .
++ PERMISSION & CONDITIONS
++ Permission is hereby granted, free of charge, to any person obtaining
++ a copy of the Font Software, to use, study, copy, merge, embed, modify,
++ redistribute, and sell modified and unmodified copies of the Font
++ Software, subject to the following conditions:
++ .
++ 1) Neither the Font Software nor any of its individual components,
++ in Original or Modified Versions, may be sold by itself.
++ .
++ 2) Original or Modified Versions of the Font Software may be bundled,
++ redistributed and/or sold with any software, provided that each copy
++ contains the above copyright notice and this license. These can be
++ included either as stand-alone text files, human-readable headers or
++ in the appropriate machine-readable metadata fields within text or
++ binary files as long as those fields can be easily viewed by the user.
++ .
++ 3) No Modified Version of the Font Software may use the Reserved Font
++ Name(s) unless explicit written permission is granted by the corresponding
++ Copyright Holder. This restriction only applies to the primary font name as
++ presented to the users.
++ .
++ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
++ Software shall not be used to promote, endorse or advertise any
++ Modified Version, except to acknowledge the contribution(s) of the
++ Copyright Holder(s) and the Author(s) or with their explicit written
++ permission.
++ .
++ 5) The Font Software, modified or unmodified, in part or in whole,
++ must be distributed entirely under this license, and must not be
++ distributed under any other license. The requirement for fonts to
++ remain under this license does not apply to any document created
++ using the Font Software.
++ .
++ TERMINATION
++ This license becomes null and void if any of the above conditions are
++ not met.
++ .
++ DISCLAIMER
++ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
++ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
++ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
++ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
++ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
++ OTHER DEALINGS IN THE FONT SOFTWARE.
diff --cc debian/docs
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e48692b73e12b53b7972b526f8ff7b7ebcc72756
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++README.md
++CHANGELOG.md
++THIRD_PARTIES.txt
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8de0fcdc08eb24efb4963b5d609af15ae434892b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++usr/include/slvs.h
++usr/lib/*/libslvs.so
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ffa6d6e1a45cc7c31b9cd6b270b90ecc39947262
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++usr/lib/*/libslvs.so.*
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9e5a1f3d7bf73b8d833bceba57c573505c4f1286
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++libslvs1t64: package-name-doesnt-match-sonames libslvs1
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..00d2965ebdb42c4ef17b2258fc5402cd26279266
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2643 @@@
++/*! Hammer.JS - v2.0.7 - 2016-04-22
++ * http://hammerjs.github.io/
++ *
++ * Copyright (c) 2016 Jorik Tangelder;
++ * Licensed under the MIT license */
++(function(window, document, exportName, undefined) {
++  'use strict';
++
++var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
++var TEST_ELEMENT = document.createElement('div');
++
++var TYPE_FUNCTION = 'function';
++
++var round = Math.round;
++var abs = Math.abs;
++var now = Date.now;
++
++/**
++ * set a timeout with a given scope
++ * @param {Function} fn
++ * @param {Number} timeout
++ * @param {Object} context
++ * @returns {number}
++ */
++function setTimeoutContext(fn, timeout, context) {
++    return setTimeout(bindFn(fn, context), timeout);
++}
++
++/**
++ * if the argument is an array, we want to execute the fn on each entry
++ * if it aint an array we don't want to do a thing.
++ * this is used by all the methods that accept a single and array argument.
++ * @param {*|Array} arg
++ * @param {String} fn
++ * @param {Object} [context]
++ * @returns {Boolean}
++ */
++function invokeArrayArg(arg, fn, context) {
++    if (Array.isArray(arg)) {
++        each(arg, context[fn], context);
++        return true;
++    }
++    return false;
++}
++
++/**
++ * walk objects and arrays
++ * @param {Object} obj
++ * @param {Function} iterator
++ * @param {Object} context
++ */
++function each(obj, iterator, context) {
++    var i;
++
++    if (!obj) {
++        return;
++    }
++
++    if (obj.forEach) {
++        obj.forEach(iterator, context);
++    } else if (obj.length !== undefined) {
++        i = 0;
++        while (i < obj.length) {
++            iterator.call(context, obj[i], i, obj);
++            i++;
++        }
++    } else {
++        for (i in obj) {
++            obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
++        }
++    }
++}
++
++/**
++ * wrap a method with a deprecation warning and stack trace
++ * @param {Function} method
++ * @param {String} name
++ * @param {String} message
++ * @returns {Function} A new function wrapping the supplied method.
++ */
++function deprecate(method, name, message) {
++    var deprecationMessage = 'DEPRECATED METHOD: ' + name + '\n' + message + ' AT \n';
++    return function() {
++        var e = new Error('get-stack-trace');
++        var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '')
++            .replace(/^\s+at\s+/gm, '')
++            .replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';
++
++        var log = window.console && (window.console.warn || window.console.log);
++        if (log) {
++            log.call(window.console, deprecationMessage, stack);
++        }
++        return method.apply(this, arguments);
++    };
++}
++
++/**
++ * extend object.
++ * means that properties in dest will be overwritten by the ones in src.
++ * @param {Object} target
++ * @param {...Object} objects_to_assign
++ * @returns {Object} target
++ */
++var assign;
++if (typeof Object.assign !== 'function') {
++    assign = function assign(target) {
++        if (target === undefined || target === null) {
++            throw new TypeError('Cannot convert undefined or null to object');
++        }
++
++        var output = Object(target);
++        for (var index = 1; index < arguments.length; index++) {
++            var source = arguments[index];
++            if (source !== undefined && source !== null) {
++                for (var nextKey in source) {
++                    if (source.hasOwnProperty(nextKey)) {
++                        output[nextKey] = source[nextKey];
++                    }
++                }
++            }
++        }
++        return output;
++    };
++} else {
++    assign = Object.assign;
++}
++
++/**
++ * extend object.
++ * means that properties in dest will be overwritten by the ones in src.
++ * @param {Object} dest
++ * @param {Object} src
++ * @param {Boolean} [merge=false]
++ * @returns {Object} dest
++ */
++var extend = deprecate(function extend(dest, src, merge) {
++    var keys = Object.keys(src);
++    var i = 0;
++    while (i < keys.length) {
++        if (!merge || (merge && dest[keys[i]] === undefined)) {
++            dest[keys[i]] = src[keys[i]];
++        }
++        i++;
++    }
++    return dest;
++}, 'extend', 'Use `assign`.');
++
++/**
++ * merge the values from src in the dest.
++ * means that properties that exist in dest will not be overwritten by src
++ * @param {Object} dest
++ * @param {Object} src
++ * @returns {Object} dest
++ */
++var merge = deprecate(function merge(dest, src) {
++    return extend(dest, src, true);
++}, 'merge', 'Use `assign`.');
++
++/**
++ * simple class inheritance
++ * @param {Function} child
++ * @param {Function} base
++ * @param {Object} [properties]
++ */
++function inherit(child, base, properties) {
++    var baseP = base.prototype,
++        childP;
++
++    childP = child.prototype = Object.create(baseP);
++    childP.constructor = child;
++    childP._super = baseP;
++
++    if (properties) {
++        assign(childP, properties);
++    }
++}
++
++/**
++ * simple function bind
++ * @param {Function} fn
++ * @param {Object} context
++ * @returns {Function}
++ */
++function bindFn(fn, context) {
++    return function boundFn() {
++        return fn.apply(context, arguments);
++    };
++}
++
++/**
++ * let a boolean value also be a function that must return a boolean
++ * this first item in args will be used as the context
++ * @param {Boolean|Function} val
++ * @param {Array} [args]
++ * @returns {Boolean}
++ */
++function boolOrFn(val, args) {
++    if (typeof val == TYPE_FUNCTION) {
++        return val.apply(args ? args[0] || undefined : undefined, args);
++    }
++    return val;
++}
++
++/**
++ * use the val2 when val1 is undefined
++ * @param {*} val1
++ * @param {*} val2
++ * @returns {*}
++ */
++function ifUndefined(val1, val2) {
++    return (val1 === undefined) ? val2 : val1;
++}
++
++/**
++ * addEventListener with multiple events at once
++ * @param {EventTarget} target
++ * @param {String} types
++ * @param {Function} handler
++ */
++function addEventListeners(target, types, handler) {
++    each(splitStr(types), function(type) {
++        target.addEventListener(type, handler, false);
++    });
++}
++
++/**
++ * removeEventListener with multiple events at once
++ * @param {EventTarget} target
++ * @param {String} types
++ * @param {Function} handler
++ */
++function removeEventListeners(target, types, handler) {
++    each(splitStr(types), function(type) {
++        target.removeEventListener(type, handler, false);
++    });
++}
++
++/**
++ * find if a node is in the given parent
++ * @method hasParent
++ * @param {HTMLElement} node
++ * @param {HTMLElement} parent
++ * @return {Boolean} found
++ */
++function hasParent(node, parent) {
++    while (node) {
++        if (node == parent) {
++            return true;
++        }
++        node = node.parentNode;
++    }
++    return false;
++}
++
++/**
++ * small indexOf wrapper
++ * @param {String} str
++ * @param {String} find
++ * @returns {Boolean} found
++ */
++function inStr(str, find) {
++    return str.indexOf(find) > -1;
++}
++
++/**
++ * split string on whitespace
++ * @param {String} str
++ * @returns {Array} words
++ */
++function splitStr(str) {
++    return str.trim().split(/\s+/g);
++}
++
++/**
++ * find if a array contains the object using indexOf or a simple polyFill
++ * @param {Array} src
++ * @param {String} find
++ * @param {String} [findByKey]
++ * @return {Boolean|Number} false when not found, or the index
++ */
++function inArray(src, find, findByKey) {
++    if (src.indexOf && !findByKey) {
++        return src.indexOf(find);
++    } else {
++        var i = 0;
++        while (i < src.length) {
++            if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) {
++                return i;
++            }
++            i++;
++        }
++        return -1;
++    }
++}
++
++/**
++ * convert array-like objects to real arrays
++ * @param {Object} obj
++ * @returns {Array}
++ */
++function toArray(obj) {
++    return Array.prototype.slice.call(obj, 0);
++}
++
++/**
++ * unique array with objects based on a key (like 'id') or just by the array's value
++ * @param {Array} src [{id:1},{id:2},{id:1}]
++ * @param {String} [key]
++ * @param {Boolean} [sort=False]
++ * @returns {Array} [{id:1},{id:2}]
++ */
++function uniqueArray(src, key, sort) {
++    var results = [];
++    var values = [];
++    var i = 0;
++
++    while (i < src.length) {
++        var val = key ? src[i][key] : src[i];
++        if (inArray(values, val) < 0) {
++            results.push(src[i]);
++        }
++        values[i] = val;
++        i++;
++    }
++
++    if (sort) {
++        if (!key) {
++            results = results.sort();
++        } else {
++            results = results.sort(function sortUniqueArray(a, b) {
++                return a[key] > b[key];
++            });
++        }
++    }
++
++    return results;
++}
++
++/**
++ * get the prefixed property
++ * @param {Object} obj
++ * @param {String} property
++ * @returns {String|Undefined} prefixed
++ */
++function prefixed(obj, property) {
++    var prefix, prop;
++    var camelProp = property[0].toUpperCase() + property.slice(1);
++
++    var i = 0;
++    while (i < VENDOR_PREFIXES.length) {
++        prefix = VENDOR_PREFIXES[i];
++        prop = (prefix) ? prefix + camelProp : property;
++
++        if (prop in obj) {
++            return prop;
++        }
++        i++;
++    }
++    return undefined;
++}
++
++/**
++ * get a unique id
++ * @returns {number} uniqueId
++ */
++var _uniqueId = 1;
++function uniqueId() {
++    return _uniqueId++;
++}
++
++/**
++ * get the window object of an element
++ * @param {HTMLElement} element
++ * @returns {DocumentView|Window}
++ */
++function getWindowForElement(element) {
++    var doc = element.ownerDocument || element;
++    return (doc.defaultView || doc.parentWindow || window);
++}
++
++var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
++
++var SUPPORT_TOUCH = ('ontouchstart' in window);
++var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined;
++var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
++
++var INPUT_TYPE_TOUCH = 'touch';
++var INPUT_TYPE_PEN = 'pen';
++var INPUT_TYPE_MOUSE = 'mouse';
++var INPUT_TYPE_KINECT = 'kinect';
++
++var COMPUTE_INTERVAL = 25;
++
++var INPUT_START = 1;
++var INPUT_MOVE = 2;
++var INPUT_END = 4;
++var INPUT_CANCEL = 8;
++
++var DIRECTION_NONE = 1;
++var DIRECTION_LEFT = 2;
++var DIRECTION_RIGHT = 4;
++var DIRECTION_UP = 8;
++var DIRECTION_DOWN = 16;
++
++var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
++var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
++var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
++
++var PROPS_XY = ['x', 'y'];
++var PROPS_CLIENT_XY = ['clientX', 'clientY'];
++
++/**
++ * create new input type manager
++ * @param {Manager} manager
++ * @param {Function} callback
++ * @returns {Input}
++ * @constructor
++ */
++function Input(manager, callback) {
++    var self = this;
++    this.manager = manager;
++    this.callback = callback;
++    this.element = manager.element;
++    this.target = manager.options.inputTarget;
++
++    // smaller wrapper around the handler, for the scope and the enabled state of the manager,
++    // so when disabled the input events are completely bypassed.
++    this.domHandler = function(ev) {
++        if (boolOrFn(manager.options.enable, [manager])) {
++            self.handler(ev);
++        }
++    };
++
++    this.init();
++
++}
++
++Input.prototype = {
++    /**
++     * should handle the inputEvent data and trigger the callback
++     * @virtual
++     */
++    handler: function() { },
++
++    /**
++     * bind the events
++     */
++    init: function() {
++        this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
++        this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
++        this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
++    },
++
++    /**
++     * unbind the events
++     */
++    destroy: function() {
++        this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
++        this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
++        this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
++    }
++};
++
++/**
++ * create new input type manager
++ * called by the Manager constructor
++ * @param {Hammer} manager
++ * @returns {Input}
++ */
++function createInputInstance(manager) {
++    var Type;
++    var inputClass = manager.options.inputClass;
++
++    if (inputClass) {
++        Type = inputClass;
++    } else if (SUPPORT_POINTER_EVENTS) {
++        Type = PointerEventInput;
++    } else if (SUPPORT_ONLY_TOUCH) {
++        Type = TouchInput;
++    } else if (!SUPPORT_TOUCH) {
++        Type = MouseInput;
++    } else {
++        Type = TouchMouseInput;
++    }
++    return new (Type)(manager, inputHandler);
++}
++
++/**
++ * handle input events
++ * @param {Manager} manager
++ * @param {String} eventType
++ * @param {Object} input
++ */
++function inputHandler(manager, eventType, input) {
++    var pointersLen = input.pointers.length;
++    var changedPointersLen = input.changedPointers.length;
++    var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0));
++    var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0));
++
++    input.isFirst = !!isFirst;
++    input.isFinal = !!isFinal;
++
++    if (isFirst) {
++        manager.session = {};
++    }
++
++    // source event is the normalized value of the domEvents
++    // like 'touchstart, mouseup, pointerdown'
++    input.eventType = eventType;
++
++    // compute scale, rotation etc
++    computeInputData(manager, input);
++
++    // emit secret event
++    manager.emit('hammer.input', input);
++
++    manager.recognize(input);
++    manager.session.prevInput = input;
++}
++
++/**
++ * extend the data with some usable properties like scale, rotate, velocity etc
++ * @param {Object} manager
++ * @param {Object} input
++ */
++function computeInputData(manager, input) {
++    var session = manager.session;
++    var pointers = input.pointers;
++    var pointersLength = pointers.length;
++
++    // store the first input to calculate the distance and direction
++    if (!session.firstInput) {
++        session.firstInput = simpleCloneInputData(input);
++    }
++
++    // to compute scale and rotation we need to store the multiple touches
++    if (pointersLength > 1 && !session.firstMultiple) {
++        session.firstMultiple = simpleCloneInputData(input);
++    } else if (pointersLength === 1) {
++        session.firstMultiple = false;
++    }
++
++    var firstInput = session.firstInput;
++    var firstMultiple = session.firstMultiple;
++    var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
++
++    var center = input.center = getCenter(pointers);
++    input.timeStamp = now();
++    input.deltaTime = input.timeStamp - firstInput.timeStamp;
++
++    input.angle = getAngle(offsetCenter, center);
++    input.distance = getDistance(offsetCenter, center);
++
++    computeDeltaXY(session, input);
++    input.offsetDirection = getDirection(input.deltaX, input.deltaY);
++
++    var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
++    input.overallVelocityX = overallVelocity.x;
++    input.overallVelocityY = overallVelocity.y;
++    input.overallVelocity = (abs(overallVelocity.x) > abs(overallVelocity.y)) ? overallVelocity.x : overallVelocity.y;
++
++    input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
++    input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
++
++    input.maxPointers = !session.prevInput ? input.pointers.length : ((input.pointers.length >
++        session.prevInput.maxPointers) ? input.pointers.length : session.prevInput.maxPointers);
++
++    computeIntervalInputData(session, input);
++
++    // find the correct target
++    var target = manager.element;
++    if (hasParent(input.srcEvent.target, target)) {
++        target = input.srcEvent.target;
++    }
++    input.target = target;
++}
++
++function computeDeltaXY(session, input) {
++    var center = input.center;
++    var offset = session.offsetDelta || {};
++    var prevDelta = session.prevDelta || {};
++    var prevInput = session.prevInput || {};
++
++    if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
++        prevDelta = session.prevDelta = {
++            x: prevInput.deltaX || 0,
++            y: prevInput.deltaY || 0
++        };
++
++        offset = session.offsetDelta = {
++            x: center.x,
++            y: center.y
++        };
++    }
++
++    input.deltaX = prevDelta.x + (center.x - offset.x);
++    input.deltaY = prevDelta.y + (center.y - offset.y);
++}
++
++/**
++ * velocity is calculated every x ms
++ * @param {Object} session
++ * @param {Object} input
++ */
++function computeIntervalInputData(session, input) {
++    var last = session.lastInterval || input,
++        deltaTime = input.timeStamp - last.timeStamp,
++        velocity, velocityX, velocityY, direction;
++
++    if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
++        var deltaX = input.deltaX - last.deltaX;
++        var deltaY = input.deltaY - last.deltaY;
++
++        var v = getVelocity(deltaTime, deltaX, deltaY);
++        velocityX = v.x;
++        velocityY = v.y;
++        velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
++        direction = getDirection(deltaX, deltaY);
++
++        session.lastInterval = input;
++    } else {
++        // use latest velocity info if it doesn't overtake a minimum period
++        velocity = last.velocity;
++        velocityX = last.velocityX;
++        velocityY = last.velocityY;
++        direction = last.direction;
++    }
++
++    input.velocity = velocity;
++    input.velocityX = velocityX;
++    input.velocityY = velocityY;
++    input.direction = direction;
++}
++
++/**
++ * create a simple clone from the input used for storage of firstInput and firstMultiple
++ * @param {Object} input
++ * @returns {Object} clonedInputData
++ */
++function simpleCloneInputData(input) {
++    // make a simple copy of the pointers because we will get a reference if we don't
++    // we only need clientXY for the calculations
++    var pointers = [];
++    var i = 0;
++    while (i < input.pointers.length) {
++        pointers[i] = {
++            clientX: round(input.pointers[i].clientX),
++            clientY: round(input.pointers[i].clientY)
++        };
++        i++;
++    }
++
++    return {
++        timeStamp: now(),
++        pointers: pointers,
++        center: getCenter(pointers),
++        deltaX: input.deltaX,
++        deltaY: input.deltaY
++    };
++}
++
++/**
++ * get the center of all the pointers
++ * @param {Array} pointers
++ * @return {Object} center contains `x` and `y` properties
++ */
++function getCenter(pointers) {
++    var pointersLength = pointers.length;
++
++    // no need to loop when only one touch
++    if (pointersLength === 1) {
++        return {
++            x: round(pointers[0].clientX),
++            y: round(pointers[0].clientY)
++        };
++    }
++
++    var x = 0, y = 0, i = 0;
++    while (i < pointersLength) {
++        x += pointers[i].clientX;
++        y += pointers[i].clientY;
++        i++;
++    }
++
++    return {
++        x: round(x / pointersLength),
++        y: round(y / pointersLength)
++    };
++}
++
++/**
++ * calculate the velocity between two points. unit is in px per ms.
++ * @param {Number} deltaTime
++ * @param {Number} x
++ * @param {Number} y
++ * @return {Object} velocity `x` and `y`
++ */
++function getVelocity(deltaTime, x, y) {
++    return {
++        x: x / deltaTime || 0,
++        y: y / deltaTime || 0
++    };
++}
++
++/**
++ * get the direction between two points
++ * @param {Number} x
++ * @param {Number} y
++ * @return {Number} direction
++ */
++function getDirection(x, y) {
++    if (x === y) {
++        return DIRECTION_NONE;
++    }
++
++    if (abs(x) >= abs(y)) {
++        return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
++    }
++    return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
++}
++
++/**
++ * calculate the absolute distance between two points
++ * @param {Object} p1 {x, y}
++ * @param {Object} p2 {x, y}
++ * @param {Array} [props] containing x and y keys
++ * @return {Number} distance
++ */
++function getDistance(p1, p2, props) {
++    if (!props) {
++        props = PROPS_XY;
++    }
++    var x = p2[props[0]] - p1[props[0]],
++        y = p2[props[1]] - p1[props[1]];
++
++    return Math.sqrt((x * x) + (y * y));
++}
++
++/**
++ * calculate the angle between two coordinates
++ * @param {Object} p1
++ * @param {Object} p2
++ * @param {Array} [props] containing x and y keys
++ * @return {Number} angle
++ */
++function getAngle(p1, p2, props) {
++    if (!props) {
++        props = PROPS_XY;
++    }
++    var x = p2[props[0]] - p1[props[0]],
++        y = p2[props[1]] - p1[props[1]];
++    return Math.atan2(y, x) * 180 / Math.PI;
++}
++
++/**
++ * calculate the rotation degrees between two pointersets
++ * @param {Array} start array of pointers
++ * @param {Array} end array of pointers
++ * @return {Number} rotation
++ */
++function getRotation(start, end) {
++    return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
++}
++
++/**
++ * calculate the scale factor between two pointersets
++ * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
++ * @param {Array} start array of pointers
++ * @param {Array} end array of pointers
++ * @return {Number} scale
++ */
++function getScale(start, end) {
++    return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
++}
++
++var MOUSE_INPUT_MAP = {
++    mousedown: INPUT_START,
++    mousemove: INPUT_MOVE,
++    mouseup: INPUT_END
++};
++
++var MOUSE_ELEMENT_EVENTS = 'mousedown';
++var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
++
++/**
++ * Mouse events input
++ * @constructor
++ * @extends Input
++ */
++function MouseInput() {
++    this.evEl = MOUSE_ELEMENT_EVENTS;
++    this.evWin = MOUSE_WINDOW_EVENTS;
++
++    this.pressed = false; // mousedown state
++
++    Input.apply(this, arguments);
++}
++
++inherit(MouseInput, Input, {
++    /**
++     * handle mouse events
++     * @param {Object} ev
++     */
++    handler: function MEhandler(ev) {
++        var eventType = MOUSE_INPUT_MAP[ev.type];
++
++        // on start we want to have the left mouse button down
++        if (eventType & INPUT_START && ev.button === 0) {
++            this.pressed = true;
++        }
++
++        if (eventType & INPUT_MOVE && ev.which !== 1) {
++            eventType = INPUT_END;
++        }
++
++        // mouse must be down
++        if (!this.pressed) {
++            return;
++        }
++
++        if (eventType & INPUT_END) {
++            this.pressed = false;
++        }
++
++        this.callback(this.manager, eventType, {
++            pointers: [ev],
++            changedPointers: [ev],
++            pointerType: INPUT_TYPE_MOUSE,
++            srcEvent: ev
++        });
++    }
++});
++
++var POINTER_INPUT_MAP = {
++    pointerdown: INPUT_START,
++    pointermove: INPUT_MOVE,
++    pointerup: INPUT_END,
++    pointercancel: INPUT_CANCEL,
++    pointerout: INPUT_CANCEL
++};
++
++// in IE10 the pointer types is defined as an enum
++var IE10_POINTER_TYPE_ENUM = {
++    2: INPUT_TYPE_TOUCH,
++    3: INPUT_TYPE_PEN,
++    4: INPUT_TYPE_MOUSE,
++    5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
++};
++
++var POINTER_ELEMENT_EVENTS = 'pointerdown';
++var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';
++
++// IE10 has prefixed support, and case-sensitive
++if (window.MSPointerEvent && !window.PointerEvent) {
++    POINTER_ELEMENT_EVENTS = 'MSPointerDown';
++    POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
++}
++
++/**
++ * Pointer events input
++ * @constructor
++ * @extends Input
++ */
++function PointerEventInput() {
++    this.evEl = POINTER_ELEMENT_EVENTS;
++    this.evWin = POINTER_WINDOW_EVENTS;
++
++    Input.apply(this, arguments);
++
++    this.store = (this.manager.session.pointerEvents = []);
++}
++
++inherit(PointerEventInput, Input, {
++    /**
++     * handle mouse events
++     * @param {Object} ev
++     */
++    handler: function PEhandler(ev) {
++        var store = this.store;
++        var removePointer = false;
++
++        var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
++        var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
++        var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
++
++        var isTouch = (pointerType == INPUT_TYPE_TOUCH);
++
++        // get index of the event in the store
++        var storeIndex = inArray(store, ev.pointerId, 'pointerId');
++
++        // start and mouse must be down
++        if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
++            if (storeIndex < 0) {
++                store.push(ev);
++                storeIndex = store.length - 1;
++            }
++        } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
++            removePointer = true;
++        }
++
++        // it not found, so the pointer hasn't been down (so it's probably a hover)
++        if (storeIndex < 0) {
++            return;
++        }
++
++        // update the event in the store
++        store[storeIndex] = ev;
++
++        this.callback(this.manager, eventType, {
++            pointers: store,
++            changedPointers: [ev],
++            pointerType: pointerType,
++            srcEvent: ev
++        });
++
++        if (removePointer) {
++            // remove from the store
++            store.splice(storeIndex, 1);
++        }
++    }
++});
++
++var SINGLE_TOUCH_INPUT_MAP = {
++    touchstart: INPUT_START,
++    touchmove: INPUT_MOVE,
++    touchend: INPUT_END,
++    touchcancel: INPUT_CANCEL
++};
++
++var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
++var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
++
++/**
++ * Touch events input
++ * @constructor
++ * @extends Input
++ */
++function SingleTouchInput() {
++    this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
++    this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
++    this.started = false;
++
++    Input.apply(this, arguments);
++}
++
++inherit(SingleTouchInput, Input, {
++    handler: function TEhandler(ev) {
++        var type = SINGLE_TOUCH_INPUT_MAP[ev.type];
++
++        // should we handle the touch events?
++        if (type === INPUT_START) {
++            this.started = true;
++        }
++
++        if (!this.started) {
++            return;
++        }
++
++        var touches = normalizeSingleTouches.call(this, ev, type);
++
++        // when done, reset the started state
++        if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
++            this.started = false;
++        }
++
++        this.callback(this.manager, type, {
++            pointers: touches[0],
++            changedPointers: touches[1],
++            pointerType: INPUT_TYPE_TOUCH,
++            srcEvent: ev
++        });
++    }
++});
++
++/**
++ * @this {TouchInput}
++ * @param {Object} ev
++ * @param {Number} type flag
++ * @returns {undefined|Array} [all, changed]
++ */
++function normalizeSingleTouches(ev, type) {
++    var all = toArray(ev.touches);
++    var changed = toArray(ev.changedTouches);
++
++    if (type & (INPUT_END | INPUT_CANCEL)) {
++        all = uniqueArray(all.concat(changed), 'identifier', true);
++    }
++
++    return [all, changed];
++}
++
++var TOUCH_INPUT_MAP = {
++    touchstart: INPUT_START,
++    touchmove: INPUT_MOVE,
++    touchend: INPUT_END,
++    touchcancel: INPUT_CANCEL
++};
++
++var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
++
++/**
++ * Multi-user touch events input
++ * @constructor
++ * @extends Input
++ */
++function TouchInput() {
++    this.evTarget = TOUCH_TARGET_EVENTS;
++    this.targetIds = {};
++
++    Input.apply(this, arguments);
++}
++
++inherit(TouchInput, Input, {
++    handler: function MTEhandler(ev) {
++        var type = TOUCH_INPUT_MAP[ev.type];
++        var touches = getTouches.call(this, ev, type);
++        if (!touches) {
++            return;
++        }
++
++        this.callback(this.manager, type, {
++            pointers: touches[0],
++            changedPointers: touches[1],
++            pointerType: INPUT_TYPE_TOUCH,
++            srcEvent: ev
++        });
++    }
++});
++
++/**
++ * @this {TouchInput}
++ * @param {Object} ev
++ * @param {Number} type flag
++ * @returns {undefined|Array} [all, changed]
++ */
++function getTouches(ev, type) {
++    var allTouches = toArray(ev.touches);
++    var targetIds = this.targetIds;
++
++    // when there is only one touch, the process can be simplified
++    if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
++        targetIds[allTouches[0].identifier] = true;
++        return [allTouches, allTouches];
++    }
++
++    var i,
++        targetTouches,
++        changedTouches = toArray(ev.changedTouches),
++        changedTargetTouches = [],
++        target = this.target;
++
++    // get target touches from touches
++    targetTouches = allTouches.filter(function(touch) {
++        return hasParent(touch.target, target);
++    });
++
++    // collect touches
++    if (type === INPUT_START) {
++        i = 0;
++        while (i < targetTouches.length) {
++            targetIds[targetTouches[i].identifier] = true;
++            i++;
++        }
++    }
++
++    // filter changed touches to only contain touches that exist in the collected target ids
++    i = 0;
++    while (i < changedTouches.length) {
++        if (targetIds[changedTouches[i].identifier]) {
++            changedTargetTouches.push(changedTouches[i]);
++        }
++
++        // cleanup removed touches
++        if (type & (INPUT_END | INPUT_CANCEL)) {
++            delete targetIds[changedTouches[i].identifier];
++        }
++        i++;
++    }
++
++    if (!changedTargetTouches.length) {
++        return;
++    }
++
++    return [
++        // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
++        uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true),
++        changedTargetTouches
++    ];
++}
++
++/**
++ * Combined touch and mouse input
++ *
++ * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
++ * This because touch devices also emit mouse events while doing a touch.
++ *
++ * @constructor
++ * @extends Input
++ */
++
++var DEDUP_TIMEOUT = 2500;
++var DEDUP_DISTANCE = 25;
++
++function TouchMouseInput() {
++    Input.apply(this, arguments);
++
++    var handler = bindFn(this.handler, this);
++    this.touch = new TouchInput(this.manager, handler);
++    this.mouse = new MouseInput(this.manager, handler);
++
++    this.primaryTouch = null;
++    this.lastTouches = [];
++}
++
++inherit(TouchMouseInput, Input, {
++    /**
++     * handle mouse and touch events
++     * @param {Hammer} manager
++     * @param {String} inputEvent
++     * @param {Object} inputData
++     */
++    handler: function TMEhandler(manager, inputEvent, inputData) {
++        var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH),
++            isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE);
++
++        if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {
++            return;
++        }
++
++        // when we're in a touch event, record touches to  de-dupe synthetic mouse event
++        if (isTouch) {
++            recordTouches.call(this, inputEvent, inputData);
++        } else if (isMouse && isSyntheticEvent.call(this, inputData)) {
++            return;
++        }
++
++        this.callback(manager, inputEvent, inputData);
++    },
++
++    /**
++     * remove the event listeners
++     */
++    destroy: function destroy() {
++        this.touch.destroy();
++        this.mouse.destroy();
++    }
++});
++
++function recordTouches(eventType, eventData) {
++    if (eventType & INPUT_START) {
++        this.primaryTouch = eventData.changedPointers[0].identifier;
++        setLastTouch.call(this, eventData);
++    } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
++        setLastTouch.call(this, eventData);
++    }
++}
++
++function setLastTouch(eventData) {
++    var touch = eventData.changedPointers[0];
++
++    if (touch.identifier === this.primaryTouch) {
++        var lastTouch = {x: touch.clientX, y: touch.clientY};
++        this.lastTouches.push(lastTouch);
++        var lts = this.lastTouches;
++        var removeLastTouch = function() {
++            var i = lts.indexOf(lastTouch);
++            if (i > -1) {
++                lts.splice(i, 1);
++            }
++        };
++        setTimeout(removeLastTouch, DEDUP_TIMEOUT);
++    }
++}
++
++function isSyntheticEvent(eventData) {
++    var x = eventData.srcEvent.clientX, y = eventData.srcEvent.clientY;
++    for (var i = 0; i < this.lastTouches.length; i++) {
++        var t = this.lastTouches[i];
++        var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y);
++        if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {
++            return true;
++        }
++    }
++    return false;
++}
++
++var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
++var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;
++
++// magical touchAction value
++var TOUCH_ACTION_COMPUTE = 'compute';
++var TOUCH_ACTION_AUTO = 'auto';
++var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
++var TOUCH_ACTION_NONE = 'none';
++var TOUCH_ACTION_PAN_X = 'pan-x';
++var TOUCH_ACTION_PAN_Y = 'pan-y';
++var TOUCH_ACTION_MAP = getTouchActionProps();
++
++/**
++ * Touch Action
++ * sets the touchAction property or uses the js alternative
++ * @param {Manager} manager
++ * @param {String} value
++ * @constructor
++ */
++function TouchAction(manager, value) {
++    this.manager = manager;
++    this.set(value);
++}
++
++TouchAction.prototype = {
++    /**
++     * set the touchAction value on the element or enable the polyfill
++     * @param {String} value
++     */
++    set: function(value) {
++        // find out the touch-action by the event handlers
++        if (value == TOUCH_ACTION_COMPUTE) {
++            value = this.compute();
++        }
++
++        if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {
++            this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
++        }
++        this.actions = value.toLowerCase().trim();
++    },
++
++    /**
++     * just re-set the touchAction value
++     */
++    update: function() {
++        this.set(this.manager.options.touchAction);
++    },
++
++    /**
++     * compute the value for the touchAction property based on the recognizer's settings
++     * @returns {String} value
++     */
++    compute: function() {
++        var actions = [];
++        each(this.manager.recognizers, function(recognizer) {
++            if (boolOrFn(recognizer.options.enable, [recognizer])) {
++                actions = actions.concat(recognizer.getTouchAction());
++            }
++        });
++        return cleanTouchActions(actions.join(' '));
++    },
++
++    /**
++     * this method is called on each input cycle and provides the preventing of the browser behavior
++     * @param {Object} input
++     */
++    preventDefaults: function(input) {
++        var srcEvent = input.srcEvent;
++        var direction = input.offsetDirection;
++
++        // if the touch action did prevented once this session
++        if (this.manager.session.prevented) {
++            srcEvent.preventDefault();
++            return;
++        }
++
++        var actions = this.actions;
++        var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
++        var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
++        var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];
++
++        if (hasNone) {
++            //do not prevent defaults if this is a tap gesture
++
++            var isTapPointer = input.pointers.length === 1;
++            var isTapMovement = input.distance < 2;
++            var isTapTouchTime = input.deltaTime < 250;
++
++            if (isTapPointer && isTapMovement && isTapTouchTime) {
++                return;
++            }
++        }
++
++        if (hasPanX && hasPanY) {
++            // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent
++            return;
++        }
++
++        if (hasNone ||
++            (hasPanY && direction & DIRECTION_HORIZONTAL) ||
++            (hasPanX && direction & DIRECTION_VERTICAL)) {
++            return this.preventSrc(srcEvent);
++        }
++    },
++
++    /**
++     * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
++     * @param {Object} srcEvent
++     */
++    preventSrc: function(srcEvent) {
++        this.manager.session.prevented = true;
++        srcEvent.preventDefault();
++    }
++};
++
++/**
++ * when the touchActions are collected they are not a valid value, so we need to clean things up. *
++ * @param {String} actions
++ * @returns {*}
++ */
++function cleanTouchActions(actions) {
++    // none
++    if (inStr(actions, TOUCH_ACTION_NONE)) {
++        return TOUCH_ACTION_NONE;
++    }
++
++    var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
++    var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
++
++    // if both pan-x and pan-y are set (different recognizers
++    // for different directions, e.g. horizontal pan but vertical swipe?)
++    // we need none (as otherwise with pan-x pan-y combined none of these
++    // recognizers will work, since the browser would handle all panning
++    if (hasPanX && hasPanY) {
++        return TOUCH_ACTION_NONE;
++    }
++
++    // pan-x OR pan-y
++    if (hasPanX || hasPanY) {
++        return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
++    }
++
++    // manipulation
++    if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
++        return TOUCH_ACTION_MANIPULATION;
++    }
++
++    return TOUCH_ACTION_AUTO;
++}
++
++function getTouchActionProps() {
++    if (!NATIVE_TOUCH_ACTION) {
++        return false;
++    }
++    var touchMap = {};
++    var cssSupports = window.CSS && window.CSS.supports;
++    ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function(val) {
++
++        // If css.supports is not supported but there is native touch-action assume it supports
++        // all values. This is the case for IE 10 and 11.
++        touchMap[val] = cssSupports ? window.CSS.supports('touch-action', val) : true;
++    });
++    return touchMap;
++}
++
++/**
++ * Recognizer flow explained; *
++ * All recognizers have the initial state of POSSIBLE when a input session starts.
++ * The definition of a input session is from the first input until the last input, with all it's movement in it. *
++ * Example session for mouse-input: mousedown -> mousemove -> mouseup
++ *
++ * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
++ * which determines with state it should be.
++ *
++ * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
++ * POSSIBLE to give it another change on the next cycle.
++ *
++ *               Possible
++ *                  |
++ *            +-----+---------------+
++ *            |                     |
++ *      +-----+-----+               |
++ *      |           |               |
++ *   Failed      Cancelled          |
++ *                          +-------+------+
++ *                          |              |
++ *                      Recognized       Began
++ *                                         |
++ *                                      Changed
++ *                                         |
++ *                                  Ended/Recognized
++ */
++var STATE_POSSIBLE = 1;
++var STATE_BEGAN = 2;
++var STATE_CHANGED = 4;
++var STATE_ENDED = 8;
++var STATE_RECOGNIZED = STATE_ENDED;
++var STATE_CANCELLED = 16;
++var STATE_FAILED = 32;
++
++/**
++ * Recognizer
++ * Every recognizer needs to extend from this class.
++ * @constructor
++ * @param {Object} options
++ */
++function Recognizer(options) {
++    this.options = assign({}, this.defaults, options || {});
++
++    this.id = uniqueId();
++
++    this.manager = null;
++
++    // default is enable true
++    this.options.enable = ifUndefined(this.options.enable, true);
++
++    this.state = STATE_POSSIBLE;
++
++    this.simultaneous = {};
++    this.requireFail = [];
++}
++
++Recognizer.prototype = {
++    /**
++     * @virtual
++     * @type {Object}
++     */
++    defaults: {},
++
++    /**
++     * set options
++     * @param {Object} options
++     * @return {Recognizer}
++     */
++    set: function(options) {
++        assign(this.options, options);
++
++        // also update the touchAction, in case something changed about the directions/enabled state
++        this.manager && this.manager.touchAction.update();
++        return this;
++    },
++
++    /**
++     * recognize simultaneous with an other recognizer.
++     * @param {Recognizer} otherRecognizer
++     * @returns {Recognizer} this
++     */
++    recognizeWith: function(otherRecognizer) {
++        if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
++            return this;
++        }
++
++        var simultaneous = this.simultaneous;
++        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
++        if (!simultaneous[otherRecognizer.id]) {
++            simultaneous[otherRecognizer.id] = otherRecognizer;
++            otherRecognizer.recognizeWith(this);
++        }
++        return this;
++    },
++
++    /**
++     * drop the simultaneous link. it doesnt remove the link on the other recognizer.
++     * @param {Recognizer} otherRecognizer
++     * @returns {Recognizer} this
++     */
++    dropRecognizeWith: function(otherRecognizer) {
++        if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
++            return this;
++        }
++
++        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
++        delete this.simultaneous[otherRecognizer.id];
++        return this;
++    },
++
++    /**
++     * recognizer can only run when an other is failing
++     * @param {Recognizer} otherRecognizer
++     * @returns {Recognizer} this
++     */
++    requireFailure: function(otherRecognizer) {
++        if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
++            return this;
++        }
++
++        var requireFail = this.requireFail;
++        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
++        if (inArray(requireFail, otherRecognizer) === -1) {
++            requireFail.push(otherRecognizer);
++            otherRecognizer.requireFailure(this);
++        }
++        return this;
++    },
++
++    /**
++     * drop the requireFailure link. it does not remove the link on the other recognizer.
++     * @param {Recognizer} otherRecognizer
++     * @returns {Recognizer} this
++     */
++    dropRequireFailure: function(otherRecognizer) {
++        if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
++            return this;
++        }
++
++        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
++        var index = inArray(this.requireFail, otherRecognizer);
++        if (index > -1) {
++            this.requireFail.splice(index, 1);
++        }
++        return this;
++    },
++
++    /**
++     * has require failures boolean
++     * @returns {boolean}
++     */
++    hasRequireFailures: function() {
++        return this.requireFail.length > 0;
++    },
++
++    /**
++     * if the recognizer can recognize simultaneous with an other recognizer
++     * @param {Recognizer} otherRecognizer
++     * @returns {Boolean}
++     */
++    canRecognizeWith: function(otherRecognizer) {
++        return !!this.simultaneous[otherRecognizer.id];
++    },
++
++    /**
++     * You should use `tryEmit` instead of `emit` directly to check
++     * that all the needed recognizers has failed before emitting.
++     * @param {Object} input
++     */
++    emit: function(input) {
++        var self = this;
++        var state = this.state;
++
++        function emit(event) {
++            self.manager.emit(event, input);
++        }
++
++        // 'panstart' and 'panmove'
++        if (state < STATE_ENDED) {
++            emit(self.options.event + stateStr(state));
++        }
++
++        emit(self.options.event); // simple 'eventName' events
++
++        if (input.additionalEvent) { // additional event(panleft, panright, pinchin, pinchout...)
++            emit(input.additionalEvent);
++        }
++
++        // panend and pancancel
++        if (state >= STATE_ENDED) {
++            emit(self.options.event + stateStr(state));
++        }
++    },
++
++    /**
++     * Check that all the require failure recognizers has failed,
++     * if true, it emits a gesture event,
++     * otherwise, setup the state to FAILED.
++     * @param {Object} input
++     */
++    tryEmit: function(input) {
++        if (this.canEmit()) {
++            return this.emit(input);
++        }
++        // it's failing anyway
++        this.state = STATE_FAILED;
++    },
++
++    /**
++     * can we emit?
++     * @returns {boolean}
++     */
++    canEmit: function() {
++        var i = 0;
++        while (i < this.requireFail.length) {
++            if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
++                return false;
++            }
++            i++;
++        }
++        return true;
++    },
++
++    /**
++     * update the recognizer
++     * @param {Object} inputData
++     */
++    recognize: function(inputData) {
++        // make a new copy of the inputData
++        // so we can change the inputData without messing up the other recognizers
++        var inputDataClone = assign({}, inputData);
++
++        // is is enabled and allow recognizing?
++        if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
++            this.reset();
++            this.state = STATE_FAILED;
++            return;
++        }
++
++        // reset when we've reached the end
++        if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
++            this.state = STATE_POSSIBLE;
++        }
++
++        this.state = this.process(inputDataClone);
++
++        // the recognizer has recognized a gesture
++        // so trigger an event
++        if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
++            this.tryEmit(inputDataClone);
++        }
++    },
++
++    /**
++     * return the state of the recognizer
++     * the actual recognizing happens in this method
++     * @virtual
++     * @param {Object} inputData
++     * @returns {Const} STATE
++     */
++    process: function(inputData) { }, // jshint ignore:line
++
++    /**
++     * return the preferred touch-action
++     * @virtual
++     * @returns {Array}
++     */
++    getTouchAction: function() { },
++
++    /**
++     * called when the gesture isn't allowed to recognize
++     * like when another is being recognized or it is disabled
++     * @virtual
++     */
++    reset: function() { }
++};
++
++/**
++ * get a usable string, used as event postfix
++ * @param {Const} state
++ * @returns {String} state
++ */
++function stateStr(state) {
++    if (state & STATE_CANCELLED) {
++        return 'cancel';
++    } else if (state & STATE_ENDED) {
++        return 'end';
++    } else if (state & STATE_CHANGED) {
++        return 'move';
++    } else if (state & STATE_BEGAN) {
++        return 'start';
++    }
++    return '';
++}
++
++/**
++ * direction cons to string
++ * @param {Const} direction
++ * @returns {String}
++ */
++function directionStr(direction) {
++    if (direction == DIRECTION_DOWN) {
++        return 'down';
++    } else if (direction == DIRECTION_UP) {
++        return 'up';
++    } else if (direction == DIRECTION_LEFT) {
++        return 'left';
++    } else if (direction == DIRECTION_RIGHT) {
++        return 'right';
++    }
++    return '';
++}
++
++/**
++ * get a recognizer by name if it is bound to a manager
++ * @param {Recognizer|String} otherRecognizer
++ * @param {Recognizer} recognizer
++ * @returns {Recognizer}
++ */
++function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
++    var manager = recognizer.manager;
++    if (manager) {
++        return manager.get(otherRecognizer);
++    }
++    return otherRecognizer;
++}
++
++/**
++ * This recognizer is just used as a base for the simple attribute recognizers.
++ * @constructor
++ * @extends Recognizer
++ */
++function AttrRecognizer() {
++    Recognizer.apply(this, arguments);
++}
++
++inherit(AttrRecognizer, Recognizer, {
++    /**
++     * @namespace
++     * @memberof AttrRecognizer
++     */
++    defaults: {
++        /**
++         * @type {Number}
++         * @default 1
++         */
++        pointers: 1
++    },
++
++    /**
++     * Used to check if it the recognizer receives valid input, like input.distance > 10.
++     * @memberof AttrRecognizer
++     * @param {Object} input
++     * @returns {Boolean} recognized
++     */
++    attrTest: function(input) {
++        var optionPointers = this.options.pointers;
++        return optionPointers === 0 || input.pointers.length === optionPointers;
++    },
++
++    /**
++     * Process the input and return the state for the recognizer
++     * @memberof AttrRecognizer
++     * @param {Object} input
++     * @returns {*} State
++     */
++    process: function(input) {
++        var state = this.state;
++        var eventType = input.eventType;
++
++        var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
++        var isValid = this.attrTest(input);
++
++        // on cancel input and we've recognized before, return STATE_CANCELLED
++        if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
++            return state | STATE_CANCELLED;
++        } else if (isRecognized || isValid) {
++            if (eventType & INPUT_END) {
++                return state | STATE_ENDED;
++            } else if (!(state & STATE_BEGAN)) {
++                return STATE_BEGAN;
++            }
++            return state | STATE_CHANGED;
++        }
++        return STATE_FAILED;
++    }
++});
++
++/**
++ * Pan
++ * Recognized when the pointer is down and moved in the allowed direction.
++ * @constructor
++ * @extends AttrRecognizer
++ */
++function PanRecognizer() {
++    AttrRecognizer.apply(this, arguments);
++
++    this.pX = null;
++    this.pY = null;
++}
++
++inherit(PanRecognizer, AttrRecognizer, {
++    /**
++     * @namespace
++     * @memberof PanRecognizer
++     */
++    defaults: {
++        event: 'pan',
++        threshold: 10,
++        pointers: 1,
++        direction: DIRECTION_ALL
++    },
++
++    getTouchAction: function() {
++        var direction = this.options.direction;
++        var actions = [];
++        if (direction & DIRECTION_HORIZONTAL) {
++            actions.push(TOUCH_ACTION_PAN_Y);
++        }
++        if (direction & DIRECTION_VERTICAL) {
++            actions.push(TOUCH_ACTION_PAN_X);
++        }
++        return actions;
++    },
++
++    directionTest: function(input) {
++        var options = this.options;
++        var hasMoved = true;
++        var distance = input.distance;
++        var direction = input.direction;
++        var x = input.deltaX;
++        var y = input.deltaY;
++
++        // lock to axis?
++        if (!(direction & options.direction)) {
++            if (options.direction & DIRECTION_HORIZONTAL) {
++                direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT;
++                hasMoved = x != this.pX;
++                distance = Math.abs(input.deltaX);
++            } else {
++                direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN;
++                hasMoved = y != this.pY;
++                distance = Math.abs(input.deltaY);
++            }
++        }
++        input.direction = direction;
++        return hasMoved && distance > options.threshold && direction & options.direction;
++    },
++
++    attrTest: function(input) {
++        return AttrRecognizer.prototype.attrTest.call(this, input) &&
++            (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input)));
++    },
++
++    emit: function(input) {
++
++        this.pX = input.deltaX;
++        this.pY = input.deltaY;
++
++        var direction = directionStr(input.direction);
++
++        if (direction) {
++            input.additionalEvent = this.options.event + direction;
++        }
++        this._super.emit.call(this, input);
++    }
++});
++
++/**
++ * Pinch
++ * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
++ * @constructor
++ * @extends AttrRecognizer
++ */
++function PinchRecognizer() {
++    AttrRecognizer.apply(this, arguments);
++}
++
++inherit(PinchRecognizer, AttrRecognizer, {
++    /**
++     * @namespace
++     * @memberof PinchRecognizer
++     */
++    defaults: {
++        event: 'pinch',
++        threshold: 0,
++        pointers: 2
++    },
++
++    getTouchAction: function() {
++        return [TOUCH_ACTION_NONE];
++    },
++
++    attrTest: function(input) {
++        return this._super.attrTest.call(this, input) &&
++            (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
++    },
++
++    emit: function(input) {
++        if (input.scale !== 1) {
++            var inOut = input.scale < 1 ? 'in' : 'out';
++            input.additionalEvent = this.options.event + inOut;
++        }
++        this._super.emit.call(this, input);
++    }
++});
++
++/**
++ * Press
++ * Recognized when the pointer is down for x ms without any movement.
++ * @constructor
++ * @extends Recognizer
++ */
++function PressRecognizer() {
++    Recognizer.apply(this, arguments);
++
++    this._timer = null;
++    this._input = null;
++}
++
++inherit(PressRecognizer, Recognizer, {
++    /**
++     * @namespace
++     * @memberof PressRecognizer
++     */
++    defaults: {
++        event: 'press',
++        pointers: 1,
++        time: 251, // minimal time of the pointer to be pressed
++        threshold: 9 // a minimal movement is ok, but keep it low
++    },
++
++    getTouchAction: function() {
++        return [TOUCH_ACTION_AUTO];
++    },
++
++    process: function(input) {
++        var options = this.options;
++        var validPointers = input.pointers.length === options.pointers;
++        var validMovement = input.distance < options.threshold;
++        var validTime = input.deltaTime > options.time;
++
++        this._input = input;
++
++        // we only allow little movement
++        // and we've reached an end event, so a tap is possible
++        if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) {
++            this.reset();
++        } else if (input.eventType & INPUT_START) {
++            this.reset();
++            this._timer = setTimeoutContext(function() {
++                this.state = STATE_RECOGNIZED;
++                this.tryEmit();
++            }, options.time, this);
++        } else if (input.eventType & INPUT_END) {
++            return STATE_RECOGNIZED;
++        }
++        return STATE_FAILED;
++    },
++
++    reset: function() {
++        clearTimeout(this._timer);
++    },
++
++    emit: function(input) {
++        if (this.state !== STATE_RECOGNIZED) {
++            return;
++        }
++
++        if (input && (input.eventType & INPUT_END)) {
++            this.manager.emit(this.options.event + 'up', input);
++        } else {
++            this._input.timeStamp = now();
++            this.manager.emit(this.options.event, this._input);
++        }
++    }
++});
++
++/**
++ * Rotate
++ * Recognized when two or more pointer are moving in a circular motion.
++ * @constructor
++ * @extends AttrRecognizer
++ */
++function RotateRecognizer() {
++    AttrRecognizer.apply(this, arguments);
++}
++
++inherit(RotateRecognizer, AttrRecognizer, {
++    /**
++     * @namespace
++     * @memberof RotateRecognizer
++     */
++    defaults: {
++        event: 'rotate',
++        threshold: 0,
++        pointers: 2
++    },
++
++    getTouchAction: function() {
++        return [TOUCH_ACTION_NONE];
++    },
++
++    attrTest: function(input) {
++        return this._super.attrTest.call(this, input) &&
++            (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
++    }
++});
++
++/**
++ * Swipe
++ * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
++ * @constructor
++ * @extends AttrRecognizer
++ */
++function SwipeRecognizer() {
++    AttrRecognizer.apply(this, arguments);
++}
++
++inherit(SwipeRecognizer, AttrRecognizer, {
++    /**
++     * @namespace
++     * @memberof SwipeRecognizer
++     */
++    defaults: {
++        event: 'swipe',
++        threshold: 10,
++        velocity: 0.3,
++        direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
++        pointers: 1
++    },
++
++    getTouchAction: function() {
++        return PanRecognizer.prototype.getTouchAction.call(this);
++    },
++
++    attrTest: function(input) {
++        var direction = this.options.direction;
++        var velocity;
++
++        if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
++            velocity = input.overallVelocity;
++        } else if (direction & DIRECTION_HORIZONTAL) {
++            velocity = input.overallVelocityX;
++        } else if (direction & DIRECTION_VERTICAL) {
++            velocity = input.overallVelocityY;
++        }
++
++        return this._super.attrTest.call(this, input) &&
++            direction & input.offsetDirection &&
++            input.distance > this.options.threshold &&
++            input.maxPointers == this.options.pointers &&
++            abs(velocity) > this.options.velocity && input.eventType & INPUT_END;
++    },
++
++    emit: function(input) {
++        var direction = directionStr(input.offsetDirection);
++        if (direction) {
++            this.manager.emit(this.options.event + direction, input);
++        }
++
++        this.manager.emit(this.options.event, input);
++    }
++});
++
++/**
++ * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
++ * between the given interval and position. The delay option can be used to recognize multi-taps without firing
++ * a single tap.
++ *
++ * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
++ * multi-taps being recognized.
++ * @constructor
++ * @extends Recognizer
++ */
++function TapRecognizer() {
++    Recognizer.apply(this, arguments);
++
++    // previous time and center,
++    // used for tap counting
++    this.pTime = false;
++    this.pCenter = false;
++
++    this._timer = null;
++    this._input = null;
++    this.count = 0;
++}
++
++inherit(TapRecognizer, Recognizer, {
++    /**
++     * @namespace
++     * @memberof PinchRecognizer
++     */
++    defaults: {
++        event: 'tap',
++        pointers: 1,
++        taps: 1,
++        interval: 300, // max time between the multi-tap taps
++        time: 250, // max time of the pointer to be down (like finger on the screen)
++        threshold: 9, // a minimal movement is ok, but keep it low
++        posThreshold: 10 // a multi-tap can be a bit off the initial position
++    },
++
++    getTouchAction: function() {
++        return [TOUCH_ACTION_MANIPULATION];
++    },
++
++    process: function(input) {
++        var options = this.options;
++
++        var validPointers = input.pointers.length === options.pointers;
++        var validMovement = input.distance < options.threshold;
++        var validTouchTime = input.deltaTime < options.time;
++
++        this.reset();
++
++        if ((input.eventType & INPUT_START) && (this.count === 0)) {
++            return this.failTimeout();
++        }
++
++        // we only allow little movement
++        // and we've reached an end event, so a tap is possible
++        if (validMovement && validTouchTime && validPointers) {
++            if (input.eventType != INPUT_END) {
++                return this.failTimeout();
++            }
++
++            var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true;
++            var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
++
++            this.pTime = input.timeStamp;
++            this.pCenter = input.center;
++
++            if (!validMultiTap || !validInterval) {
++                this.count = 1;
++            } else {
++                this.count += 1;
++            }
++
++            this._input = input;
++
++            // if tap count matches we have recognized it,
++            // else it has began recognizing...
++            var tapCount = this.count % options.taps;
++            if (tapCount === 0) {
++                // no failing requirements, immediately trigger the tap event
++                // or wait as long as the multitap interval to trigger
++                if (!this.hasRequireFailures()) {
++                    return STATE_RECOGNIZED;
++                } else {
++                    this._timer = setTimeoutContext(function() {
++                        this.state = STATE_RECOGNIZED;
++                        this.tryEmit();
++                    }, options.interval, this);
++                    return STATE_BEGAN;
++                }
++            }
++        }
++        return STATE_FAILED;
++    },
++
++    failTimeout: function() {
++        this._timer = setTimeoutContext(function() {
++            this.state = STATE_FAILED;
++        }, this.options.interval, this);
++        return STATE_FAILED;
++    },
++
++    reset: function() {
++        clearTimeout(this._timer);
++    },
++
++    emit: function() {
++        if (this.state == STATE_RECOGNIZED) {
++            this._input.tapCount = this.count;
++            this.manager.emit(this.options.event, this._input);
++        }
++    }
++});
++
++/**
++ * Simple way to create a manager with a default set of recognizers.
++ * @param {HTMLElement} element
++ * @param {Object} [options]
++ * @constructor
++ */
++function Hammer(element, options) {
++    options = options || {};
++    options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);
++    return new Manager(element, options);
++}
++
++/**
++ * @const {string}
++ */
++Hammer.VERSION = '2.0.7';
++
++/**
++ * default settings
++ * @namespace
++ */
++Hammer.defaults = {
++    /**
++     * set if DOM events are being triggered.
++     * But this is slower and unused by simple implementations, so disabled by default.
++     * @type {Boolean}
++     * @default false
++     */
++    domEvents: false,
++
++    /**
++     * The value for the touchAction property/fallback.
++     * When set to `compute` it will magically set the correct value based on the added recognizers.
++     * @type {String}
++     * @default compute
++     */
++    touchAction: TOUCH_ACTION_COMPUTE,
++
++    /**
++     * @type {Boolean}
++     * @default true
++     */
++    enable: true,
++
++    /**
++     * EXPERIMENTAL FEATURE -- can be removed/changed
++     * Change the parent input target element.
++     * If Null, then it is being set the to main element.
++     * @type {Null|EventTarget}
++     * @default null
++     */
++    inputTarget: null,
++
++    /**
++     * force an input class
++     * @type {Null|Function}
++     * @default null
++     */
++    inputClass: null,
++
++    /**
++     * Default recognizer setup when calling `Hammer()`
++     * When creating a new Manager these will be skipped.
++     * @type {Array}
++     */
++    preset: [
++        // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
++        [RotateRecognizer, {enable: false}],
++        [PinchRecognizer, {enable: false}, ['rotate']],
++        [SwipeRecognizer, {direction: DIRECTION_HORIZONTAL}],
++        [PanRecognizer, {direction: DIRECTION_HORIZONTAL}, ['swipe']],
++        [TapRecognizer],
++        [TapRecognizer, {event: 'doubletap', taps: 2}, ['tap']],
++        [PressRecognizer]
++    ],
++
++    /**
++     * Some CSS properties can be used to improve the working of Hammer.
++     * Add them to this method and they will be set when creating a new Manager.
++     * @namespace
++     */
++    cssProps: {
++        /**
++         * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
++         * @type {String}
++         * @default 'none'
++         */
++        userSelect: 'none',
++
++        /**
++         * Disable the Windows Phone grippers when pressing an element.
++         * @type {String}
++         * @default 'none'
++         */
++        touchSelect: 'none',
++
++        /**
++         * Disables the default callout shown when you touch and hold a touch target.
++         * On iOS, when you touch and hold a touch target such as a link, Safari displays
++         * a callout containing information about the link. This property allows you to disable that callout.
++         * @type {String}
++         * @default 'none'
++         */
++        touchCallout: 'none',
++
++        /**
++         * Specifies whether zooming is enabled. Used by IE10>
++         * @type {String}
++         * @default 'none'
++         */
++        contentZooming: 'none',
++
++        /**
++         * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
++         * @type {String}
++         * @default 'none'
++         */
++        userDrag: 'none',
++
++        /**
++         * Overrides the highlight color shown when the user taps a link or a JavaScript
++         * clickable element in iOS. This property obeys the alpha value, if specified.
++         * @type {String}
++         * @default 'rgba(0,0,0,0)'
++         */
++        tapHighlightColor: 'rgba(0,0,0,0)'
++    }
++};
++
++var STOP = 1;
++var FORCED_STOP = 2;
++
++/**
++ * Manager
++ * @param {HTMLElement} element
++ * @param {Object} [options]
++ * @constructor
++ */
++function Manager(element, options) {
++    this.options = assign({}, Hammer.defaults, options || {});
++
++    this.options.inputTarget = this.options.inputTarget || element;
++
++    this.handlers = {};
++    this.session = {};
++    this.recognizers = [];
++    this.oldCssProps = {};
++
++    this.element = element;
++    this.input = createInputInstance(this);
++    this.touchAction = new TouchAction(this, this.options.touchAction);
++
++    toggleCssProps(this, true);
++
++    each(this.options.recognizers, function(item) {
++        var recognizer = this.add(new (item[0])(item[1]));
++        item[2] && recognizer.recognizeWith(item[2]);
++        item[3] && recognizer.requireFailure(item[3]);
++    }, this);
++}
++
++Manager.prototype = {
++    /**
++     * set options
++     * @param {Object} options
++     * @returns {Manager}
++     */
++    set: function(options) {
++        assign(this.options, options);
++
++        // Options that need a little more setup
++        if (options.touchAction) {
++            this.touchAction.update();
++        }
++        if (options.inputTarget) {
++            // Clean up existing event listeners and reinitialize
++            this.input.destroy();
++            this.input.target = options.inputTarget;
++            this.input.init();
++        }
++        return this;
++    },
++
++    /**
++     * stop recognizing for this session.
++     * This session will be discarded, when a new [input]start event is fired.
++     * When forced, the recognizer cycle is stopped immediately.
++     * @param {Boolean} [force]
++     */
++    stop: function(force) {
++        this.session.stopped = force ? FORCED_STOP : STOP;
++    },
++
++    /**
++     * run the recognizers!
++     * called by the inputHandler function on every movement of the pointers (touches)
++     * it walks through all the recognizers and tries to detect the gesture that is being made
++     * @param {Object} inputData
++     */
++    recognize: function(inputData) {
++        var session = this.session;
++        if (session.stopped) {
++            return;
++        }
++
++        // run the touch-action polyfill
++        this.touchAction.preventDefaults(inputData);
++
++        var recognizer;
++        var recognizers = this.recognizers;
++
++        // this holds the recognizer that is being recognized.
++        // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
++        // if no recognizer is detecting a thing, it is set to `null`
++        var curRecognizer = session.curRecognizer;
++
++        // reset when the last recognizer is recognized
++        // or when we're in a new session
++        if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) {
++            curRecognizer = session.curRecognizer = null;
++        }
++
++        var i = 0;
++        while (i < recognizers.length) {
++            recognizer = recognizers[i];
++
++            // find out if we are allowed try to recognize the input for this one.
++            // 1.   allow if the session is NOT forced stopped (see the .stop() method)
++            // 2.   allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
++            //      that is being recognized.
++            // 3.   allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
++            //      this can be setup with the `recognizeWith()` method on the recognizer.
++            if (session.stopped !== FORCED_STOP && ( // 1
++                    !curRecognizer || recognizer == curRecognizer || // 2
++                    recognizer.canRecognizeWith(curRecognizer))) { // 3
++                recognizer.recognize(inputData);
++            } else {
++                recognizer.reset();
++            }
++
++            // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
++            // current active recognizer. but only if we don't already have an active recognizer
++            if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
++                curRecognizer = session.curRecognizer = recognizer;
++            }
++            i++;
++        }
++    },
++
++    /**
++     * get a recognizer by its event name.
++     * @param {Recognizer|String} recognizer
++     * @returns {Recognizer|Null}
++     */
++    get: function(recognizer) {
++        if (recognizer instanceof Recognizer) {
++            return recognizer;
++        }
++
++        var recognizers = this.recognizers;
++        for (var i = 0; i < recognizers.length; i++) {
++            if (recognizers[i].options.event == recognizer) {
++                return recognizers[i];
++            }
++        }
++        return null;
++    },
++
++    /**
++     * add a recognizer to the manager
++     * existing recognizers with the same event name will be removed
++     * @param {Recognizer} recognizer
++     * @returns {Recognizer|Manager}
++     */
++    add: function(recognizer) {
++        if (invokeArrayArg(recognizer, 'add', this)) {
++            return this;
++        }
++
++        // remove existing
++        var existing = this.get(recognizer.options.event);
++        if (existing) {
++            this.remove(existing);
++        }
++
++        this.recognizers.push(recognizer);
++        recognizer.manager = this;
++
++        this.touchAction.update();
++        return recognizer;
++    },
++
++    /**
++     * remove a recognizer by name or instance
++     * @param {Recognizer|String} recognizer
++     * @returns {Manager}
++     */
++    remove: function(recognizer) {
++        if (invokeArrayArg(recognizer, 'remove', this)) {
++            return this;
++        }
++
++        recognizer = this.get(recognizer);
++
++        // let's make sure this recognizer exists
++        if (recognizer) {
++            var recognizers = this.recognizers;
++            var index = inArray(recognizers, recognizer);
++
++            if (index !== -1) {
++                recognizers.splice(index, 1);
++                this.touchAction.update();
++            }
++        }
++
++        return this;
++    },
++
++    /**
++     * bind event
++     * @param {String} events
++     * @param {Function} handler
++     * @returns {EventEmitter} this
++     */
++    on: function(events, handler) {
++        if (events === undefined) {
++            return;
++        }
++        if (handler === undefined) {
++            return;
++        }
++
++        var handlers = this.handlers;
++        each(splitStr(events), function(event) {
++            handlers[event] = handlers[event] || [];
++            handlers[event].push(handler);
++        });
++        return this;
++    },
++
++    /**
++     * unbind event, leave emit blank to remove all handlers
++     * @param {String} events
++     * @param {Function} [handler]
++     * @returns {EventEmitter} this
++     */
++    off: function(events, handler) {
++        if (events === undefined) {
++            return;
++        }
++
++        var handlers = this.handlers;
++        each(splitStr(events), function(event) {
++            if (!handler) {
++                delete handlers[event];
++            } else {
++                handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
++            }
++        });
++        return this;
++    },
++
++    /**
++     * emit event to the listeners
++     * @param {String} event
++     * @param {Object} data
++     */
++    emit: function(event, data) {
++        // we also want to trigger dom events
++        if (this.options.domEvents) {
++            triggerDomEvent(event, data);
++        }
++
++        // no handlers, so skip it all
++        var handlers = this.handlers[event] && this.handlers[event].slice();
++        if (!handlers || !handlers.length) {
++            return;
++        }
++
++        data.type = event;
++        data.preventDefault = function() {
++            data.srcEvent.preventDefault();
++        };
++
++        var i = 0;
++        while (i < handlers.length) {
++            handlers[i](data);
++            i++;
++        }
++    },
++
++    /**
++     * destroy the manager and unbinds all events
++     * it doesn't unbind dom events, that is the user own responsibility
++     */
++    destroy: function() {
++        this.element && toggleCssProps(this, false);
++
++        this.handlers = {};
++        this.session = {};
++        this.input.destroy();
++        this.element = null;
++    }
++};
++
++/**
++ * add/remove the css properties as defined in manager.options.cssProps
++ * @param {Manager} manager
++ * @param {Boolean} add
++ */
++function toggleCssProps(manager, add) {
++    var element = manager.element;
++    if (!element.style) {
++        return;
++    }
++    var prop;
++    each(manager.options.cssProps, function(value, name) {
++        prop = prefixed(element.style, name);
++        if (add) {
++            manager.oldCssProps[prop] = element.style[prop];
++            element.style[prop] = value;
++        } else {
++            element.style[prop] = manager.oldCssProps[prop] || '';
++        }
++    });
++    if (!add) {
++        manager.oldCssProps = {};
++    }
++}
++
++/**
++ * trigger dom event
++ * @param {String} event
++ * @param {Object} data
++ */
++function triggerDomEvent(event, data) {
++    var gestureEvent = document.createEvent('Event');
++    gestureEvent.initEvent(event, true, true);
++    gestureEvent.gesture = data;
++    data.target.dispatchEvent(gestureEvent);
++}
++
++assign(Hammer, {
++    INPUT_START: INPUT_START,
++    INPUT_MOVE: INPUT_MOVE,
++    INPUT_END: INPUT_END,
++    INPUT_CANCEL: INPUT_CANCEL,
++
++    STATE_POSSIBLE: STATE_POSSIBLE,
++    STATE_BEGAN: STATE_BEGAN,
++    STATE_CHANGED: STATE_CHANGED,
++    STATE_ENDED: STATE_ENDED,
++    STATE_RECOGNIZED: STATE_RECOGNIZED,
++    STATE_CANCELLED: STATE_CANCELLED,
++    STATE_FAILED: STATE_FAILED,
++
++    DIRECTION_NONE: DIRECTION_NONE,
++    DIRECTION_LEFT: DIRECTION_LEFT,
++    DIRECTION_RIGHT: DIRECTION_RIGHT,
++    DIRECTION_UP: DIRECTION_UP,
++    DIRECTION_DOWN: DIRECTION_DOWN,
++    DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL,
++    DIRECTION_VERTICAL: DIRECTION_VERTICAL,
++    DIRECTION_ALL: DIRECTION_ALL,
++
++    Manager: Manager,
++    Input: Input,
++    TouchAction: TouchAction,
++
++    TouchInput: TouchInput,
++    MouseInput: MouseInput,
++    PointerEventInput: PointerEventInput,
++    TouchMouseInput: TouchMouseInput,
++    SingleTouchInput: SingleTouchInput,
++
++    Recognizer: Recognizer,
++    AttrRecognizer: AttrRecognizer,
++    Tap: TapRecognizer,
++    Pan: PanRecognizer,
++    Swipe: SwipeRecognizer,
++    Pinch: PinchRecognizer,
++    Rotate: RotateRecognizer,
++    Press: PressRecognizer,
++
++    on: addEventListeners,
++    off: removeEventListeners,
++    each: each,
++    merge: merge,
++    extend: extend,
++    assign: assign,
++    inherit: inherit,
++    bindFn: bindFn,
++    prefixed: prefixed
++});
++
++// this prevents errors when Hammer is loaded in the presence of an AMD
++//  style loader but by script tag, not by the loader.
++var freeGlobal = (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : {})); // jshint ignore:line
++freeGlobal.Hammer = Hammer;
++
++if (typeof define === 'function' && define.amd) {
++    define(function() {
++        return Hammer;
++    });
++} else if (typeof module != 'undefined' && module.exports) {
++    module.exports = Hammer;
++} else {
++    window[exportName] = Hammer;
++}
++
++})(window, document, 'Hammer');
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..08baf164bcfc529891c1a3d639dce5369f87921c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,29 @@@
++From: Anton Gladky <gladk@debian.org>
++Date: Thu, 12 May 2022 16:48:46 -0500
++Subject: Manually specify git commit hash
++
++Revise on every upstream update!
++
++Forwarded: not-needed
++Last-Update: 2022-06-30
++===================================================================
++---
++ CMakeLists.txt | 4 ++--
++ 1 file changed, 2 insertions(+), 2 deletions(-)
++
++diff --git a/CMakeLists.txt b/CMakeLists.txt
++index 399e2ca..0446e1b 100644
++--- a/CMakeLists.txt
+++++ b/CMakeLists.txt
++@@ -34,9 +34,9 @@ endif()
++ # NOTE TO PACKAGERS: The embedded git commit hash is critical for rapid bug triage when the builds
++ # can come from a variety of sources. If you are mirroring the sources or otherwise build when
++ # the .git directory is not present, please comment the following line:
++-include(GetGitCommitHash)
+++# include(GetGitCommitHash)
++ # and instead uncomment the following, adding the complete git hash of the checkout you are using:
++-# set(GIT_COMMIT_HASH 0000000000000000000000000000000000000000)
+++set(GIT_COMMIT_HASH 70bde63cb32a7f049fa56cbdf924e2695fcb2916)
++ 
++ string(SUBSTRING "${GIT_COMMIT_HASH}" 0 8 solvespace_GIT_HASH)
++ project(solvespace
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ec574f6feb3dc49dcc3b6ffd58a07e5d3ac16e5f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++From: Ryan Pavlik <ryan.pavlik@collabora.com>
++Date: Thu, 12 May 2022 16:48:46 -0500
++Subject: Add debian package version to ver string.
++
++Forwarded: not-needed
++---
++ src/config.h.in | 2 +-
++ 1 file changed, 1 insertion(+), 1 deletion(-)
++
++diff --git a/src/config.h.in b/src/config.h.in
++index 187b9cb..ab0792c 100644
++--- a/src/config.h.in
+++++ b/src/config.h.in
++@@ -1,7 +1,7 @@
++ #ifndef SOLVESPACE_CONFIG_H
++ #define SOLVESPACE_CONFIG_H
++ 
++-#define PACKAGE_VERSION "@PROJECT_VERSION@~@solvespace_GIT_HASH@"
+++#define PACKAGE_VERSION "@solvespace_VERSION_MAJOR@.@solvespace_VERSION_MINOR@ (Debian package version @DEBVERSION@)"
++ #define GIT_HASH_URL "https://github.com/solvespace/solvespace/commit/@solvespace_GIT_HASH@"
++ 
++ /* Non-OS X *nix only */
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7efb308d155f573a6f1905cb3a3abb7a9885607d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,44 @@@
++From: Ryan Pavlik <ryan.pavlik@collabora.com>
++Date: Thu, 12 May 2022 16:48:46 -0500
++Subject: Use threejs from system.
++
++Forwarded: not-needed
++---
++ res/CMakeLists.txt | 1 -
++ src/export.cpp     | 4 ++--
++ 2 files changed, 2 insertions(+), 3 deletions(-)
++
++diff --git a/res/CMakeLists.txt b/res/CMakeLists.txt
++index 7303c6f..78d2bd2 100644
++--- a/res/CMakeLists.txt
+++++ b/res/CMakeLists.txt
++@@ -295,7 +295,6 @@ add_resources(
++     shaders/edge.frag
++     shaders/edge.vert
++     shaders/outline.vert
++-    threejs/three-r111.min.js.gz
++     threejs/hammer-2.0.8.js.gz
++     threejs/SolveSpaceControls.js)
++ 
++diff --git a/src/export.cpp b/src/export.cpp
++index f1c331f..d3a47b4 100644
++--- a/src/export.cpp
+++++ b/src/export.cpp
++@@ -953,7 +953,7 @@ void SolveSpaceUI::ExportMeshAsThreeJsTo(FILE *f, const Platform::Path &filename
++     STriangle *tr;
++     Vector bndl, bndh;
++ 
++-    const std::string THREE_FN("three-r111.min.js");
+++    const std::string THREE_FN("three.js");
++     const std::string HAMMER_FN("hammer-2.0.8.js");
++     const std::string CONTROLS_FN("SolveSpaceControls.js");
++ 
++@@ -1016,7 +1016,7 @@ void SolveSpaceUI::ExportMeshAsThreeJsTo(FILE *f, const Platform::Path &filename
++     if(filename.HasExtension("html")) {
++         fprintf(f, htmlbegin,
++                 THREE_FN.c_str(),
++-                LoadStringFromGzip("threejs/" + THREE_FN + ".gz").c_str(),
+++                LoadString("threejs/" + THREE_FN).c_str(),
++                 HAMMER_FN.c_str(),
++                 LoadStringFromGzip("threejs/" + HAMMER_FN + ".gz").c_str(),
++                 CONTROLS_FN.c_str(),
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d9438651a8561e0ee2f517c60368010dfeaafaf3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,35 @@@
++From: Ryan Pavlik <ryan.pavlik@collabora.com>
++Date: Thu, 12 May 2022 16:48:46 -0500
++Subject: Use Unifont from system
++
++Forwarded: not-needed
++---
++ res/CMakeLists.txt | 1 -
++ src/resource.cpp   | 2 +-
++ 2 files changed, 1 insertion(+), 2 deletions(-)
++
++diff --git a/res/CMakeLists.txt b/res/CMakeLists.txt
++index 78d2bd2..64fc439 100644
++--- a/res/CMakeLists.txt
+++++ b/res/CMakeLists.txt
++@@ -270,7 +270,6 @@ add_resources(
++     locales/tr_TR.po
++     locales/ru_RU.po
++     locales/zh_CN.po
++-    fonts/unifont.hex.gz
++     fonts/private/0-check-false.png
++     fonts/private/1-check-true.png
++     fonts/private/2-radio-false.png
++diff --git a/src/resource.cpp b/src/resource.cpp
++index d3fa4ca..f687894 100644
++--- a/src/resource.cpp
+++++ b/src/resource.cpp
++@@ -669,7 +669,7 @@ size_t BitmapFont::GetWidth(const std::string &str) {
++ }
++ 
++ BitmapFont BitmapFont::Create() {
++-    BitmapFont Font = BitmapFont::From(LoadStringFromGzip("fonts/unifont.hex.gz"));
+++    BitmapFont Font = BitmapFont::From(LoadString("fonts/unifont.hex"));
++     // Unifont doesn't have a glyph for U+0020.
++     Font.AddGlyph(0x0020, Pixmap::Create(Pixmap::Format::RGB, 8, 16));
++     Font.AddGlyph(0xE000, LoadPng("fonts/private/0-check-false.png"));
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4745fc7da062a2f378b335e49efe85528876fff7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++01_hardcode_git_hash.patch
++02_add_debian_pkg_version.patch
++03_use_system_threejs.patch
++04_use_system_unifont.patch
diff --cc debian/rules
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..be9e87bd7452e75dba982984bf720cfe6527f77f
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,36 @@@
++#!/usr/bin/make -f
++
++export DEB_BUILD_MAINT_OPTIONS = hardening=+all
++DPKG_EXPORT_BUILDFLAGS = 1
++include /usr/share/dpkg/default.mk
++
++ifneq (,$(filter $(DEB_HOST_ARCH), armel m68k mips mipsel powerpc sh4))
++      export DEB_CXXFLAGS_MAINT_APPEND += -Wl,--no-as-needed -latomic -Wl,--as-needed
++      export DEB_LDFLAGS_MAINT_APPEND += -Wl,--no-as-needed -latomic -Wl,--as-needed
++endif
++
++# Tell CMake what the package version will be, to embed in the version string.
++# We do this for upstream's benefit, in lieu of including a git commit hash.
++CMAKEOPTS=-DDEBVERSION=$(DEB_VERSION)
++CMAKEOPTS+= -DENABLE_OPENMP=yes
++CMAKEOPTS+= -DENABLE_LTO=yes
++
++#speed up the build if we are skipping the tests
++ifneq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
++ifneq (amd64,$(DEB_HOST_ARCH))
++CMAKEOPTS+= -DENABLE_TESTS=off
++endif
++endif
++
++%:
++      dh $@
++
++override_dh_auto_configure:
++      dh_auto_configure -- $(CMAKEOPTS)
++
++override_dh_auto_test:
++ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
++ifeq (amd64,$(DEB_HOST_ARCH))
++      cd obj-* && $(MAKE) -j$(nproc) test_solvespace
++endif
++endif
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f1d77c5eb9b47c0a4f675141e933f8913070fbbe
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,96 @@@
++.TH SOLVESPACE 1 "06 Oct 2019" "3.0.0"
++.SH NAME
++solvespace \- parametric 2d/3d CAD
++.SH SYNOPSIS
++.B solvespace-cli
++.RI <command> " [options] " <filename>
++.SH "DESCRIPTION"
++.B solvespace
++is a parametric 2d/3d CAD program. Applications include:
++ 
++  * modeling 3d parts — draw with extrudes, revolves, and Boolean
++    (union / difference) operations;
++  * modeling 2d parts — draw the part as a single section, and export DXF,
++    PDF, SVG; use 3d assembly to verify fit;
++  * 3d-printed parts — export the STL or other triangle mesh expected by
++    most 3d printers;
++  * preparing CAM data — export 2d vector art for a waterjet machine or
++    laser cutter; or generate STEP or STL, for import into third-party
++    CAM software for machining;
++  * mechanism design — use the constraint solver to simulate planar or
++    spatial linkages, with pin, ball, or slide joints;
++  * plane and solid geometry — replace hand-solved trigonometry and
++    spreadsheets with a live dimensioned drawing. 
++.PP
++.SH COMMON OPTIONS
++.TP
++.B \-o, \-\-output <pattern>
++For an input file <name>.slvs, replaces the '%' symbol in <pattern>
++with <name> and uses it as output file. For example, when using
++\-\-output %-2d.png for input files f/a.slvs and f/b.slvs, output files
++f/a-2d.png and f/b-2d.png will be written.
++.TP
++.B \-v, \-\-view <direction>
++Selects the camera direction. <direction> can be one of "top", "bottom",
++"left", "right", "front", "back", or "isometric".
++.TP
++.B \-t, \-\-chord-tol <tolerance>
++Selects the chord tolerance, used for converting exact curves to
++piecewise linear, and exact surfaces into triangle meshes.
++For export commands, the unit is mm, and the default is 1.0 mm.
++For non-export commands, the unit is %, and the default is 1.0 %.
++.PP
++.SH COMMANDS
++.TP
++.B thumbnail \-\-output <pattern> \-\-size <size> \-\-view <direction> [\-\-chord-tol <tolerance>]
++Outputs a rendered view of the sketch, like the SolveSpace GUI would. <size> is <width>x<height>, in pixels. Graphics acceleration is not used, and the output may look slightly different from the GUI.
++.TP
++.B export-view \-\-output <pattern> \-\-view <direction> [\-\-chord-tol <tolerance>]
++Exports a view of the sketch, in a 2d vector format.
++.TP
++.B export-wireframe \-\-output <pattern> [\-\-chord-tol <tolerance>]
++Exports a wireframe of the sketch, in a 3d vector format.
++.TP
++.B export-mesh \-\-output <pattern> [\-\-chord-tol <tolerance>]
++Exports a triangle mesh of solids in the sketch, with exact surfaces
++being triangulated first.
++.TP
++.B export-surfaces \-\-output <pattern>
++Exports exact surfaces of solids in the sketch, if any.
++.TP
++.B regenerate [\-\-chord-tol <tolerance>]
++Reloads all imported files, regenerates the sketch, and saves it.
++Note that, although this is not an export command, it uses absolute
++chord tolerance, and can be used to prepare assemblies for export.
++.PP
++.SH FILE FORMATS
++.TP
++.B thumbnail:
++    PNG image (png)
++.TP
++.B export-view:
++    PDF file (pdf)
++    Encapsulated PostScript (eps, ps)
++    Scalable Vector Graphics (svg)
++    STEP file (step, stp)
++    DXF file (AutoCAD 2007) (dxf)
++    HPGL file (plt, hpgl)
++    G Code (ngc, txt)
++.TP
++.B export-wireframe:
++    STEP file (step, stp)
++    DXF file (AutoCAD 2007) (dxf)
++.TP
++.B export-mesh:
++    STL mesh (stl)
++    Wavefront OBJ mesh (obj)
++    Three.js-compatible mesh, with viewer (html)
++    Three.js-compatible mesh, mesh only (js)
++    Q3D Object file (q3do)
++    VRML text file (wrl)
++.TP
++.B export-surfaces:
++    STEP file (step, stp)
++.PP
++.SH "AUTHORS"
++This manual page was written by Alexander Pozdnyakov <almipo@mail.ru>,
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7885dc404311942ae279696ebd67564120072522
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,28 @@@
++.\"Created with GNOME Manpages Editor Wizard
++.\"http://sourceforge.net/projects/gmanedit2
++.TH solvespace 1 "August 15, 2016" "" "SOLVESPACE"
++
++.SH NAME
++solvespace \- a parametric 3d CAD program 
++
++.SH DESCRIPTION
++.PP
++.B modeling 3d parts -
++draw with extrudes, revolves, helix creation, and Boolean (union / difference / intersection) operations
++.PP
++.B modeling 2d parts -
++draw the part as a single section, and export DXF, PDF, SVG; use 3d assembly to verify fit
++.PP
++.B 3d-printed parts -
++export the STL or other triangle mesh expected by most 3d printers
++.PP
++.B preparing CAM data - 
++export 2d vector art for a waterjet machine or laser cutter; or generate STEP or STL, for import into third-party CAM software for machining
++.PP
++.B  mechanism design -
++use the constraint solver to simulate planar or spatial linkages, with pin, ball, or slide joints
++.PP
++.B  plane and solid geometry -
++replace hand-solved trigonometry and spreadsheets with a live dimensioned drawing
++.PP
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..681991405bb0936f36d131a8132e463b70fc0372
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++usr/bin/solvespace
++usr/bin/solvespace-cli
++usr/share
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1b4d5d66e8f33e6777e8efed51954eb81a4371db
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++usr/share/javascript/three/three.js usr/share/solvespace/threejs/three.js
++usr/share/unifont/unifont.hex usr/share/solvespace/fonts/unifont.hex
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..09bf6996ab45963a016446641996c1e8f862863b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++# These are actually resources used by the application
++solvespace: package-contains-documentation-outside-usr-share-doc usr/share/solvespace/banner.txt
++solvespace: package-contains-documentation-outside-usr-share-doc usr/share/solvespace/locales.txt
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..46ff2a223512f99ba0a1e1a3b51f4006b5762382
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++debian/solvespace.1
++debian/solvespace-cli.1
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4f6e2cf52f7fac86e476364b8b1499ff9fcdbdef
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,8 @@@
++<?xml version="1.0"?>
++<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
++    <mime-type type="application/x-solvespace">
++    <comment>SolveSpace sketch</comment>
++    <glob pattern="*.slvs"/>
++    <generic-icon name="x-office-document"/>
++  </mime-type>
++</mime-info>
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..163aaf8d82b6c54f23c45f32895dbdfdcc27b047
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++3.0 (quilt)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a799080af7b9a09914dfa33d87e9d91f299bc3fb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++## This file was written by cme command.
++## You can run 'cme edit dpkg' to modify this file.
++## You may also modify the content of this file with your favorite editor.
++
++tar-ignore=".git"
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..df86ee9f157144f6d49282df743ab2925a783b71
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,14 @@@
++
++get_all_files() {
++    find -name "*.slvs"
++}
++
++get_files_with_surfaces() {
++    # Can't export the mesh/surfaces of a file with no 3d in it, just 2d
++    get_all_files | grep -E -v "(constraint)|(request)|(link)|(contour_area)"
++}
++
++get_files_to_thumbnail() {
++    # Can't thumbnail files with embedded images: https://github.com/solvespace/solvespace/issues/905
++    get_all_files | grep -v "image"
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..180eaae8d019d8832102b36355323fd78abd83d1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,8 @@@
++Tests: htmlmesh stlmesh surfaces
++Restrictions: allow-stderr
++Depends: solvespace, findutils, grep
++Architecture: !s390x
++
++Tests: thumbnail view wireframe
++Restrictions: allow-stderr
++Depends: solvespace, findutils, grep
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f2a6323c464ae21cc756ae478a2ca6a355419f70
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++#!/bin/sh
++set -e
++set -x
++. debian/tests/common
++logname=$AUTOPKGTEST_TMP/html_mesh.txt
++(
++    get_files_with_surfaces | while read fn; do
++        echo $fn
++        mkdir -p $AUTOPKGTEST_TMP/$(dirname $fn)
++        solvespace-cli export-mesh --output $AUTOPKGTEST_TMP/%_mesh.html $fn
++    done
++) 2>&1 | tee $logname
++
++# We don't care about self-intersecting errors.
++! (grep "Error" $logname | grep -v "self-intersecting")
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..eb3b218b27638c7bfb16ccb2e936c96dfef8508a
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++#!/bin/sh
++set -e
++set -x
++. debian/tests/common
++logname=$AUTOPKGTEST_TMP/stl_mesh.txt
++(
++    get_files_with_surfaces | while read fn; do
++        echo $fn
++        mkdir -p $AUTOPKGTEST_TMP/$(dirname $fn)
++        solvespace-cli export-mesh --output $AUTOPKGTEST_TMP/%_mesh.stl $fn
++    done
++) 2>&1 | tee $logname
++
++# We don't care about self-intersecting errors.
++! (grep "Error" $logname | grep -v "self-intersecting")
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..42c5bd13c0f0f143a6bb1ea202d2895c85075ae1
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,14 @@@
++#!/bin/sh
++set -e
++set -x
++. debian/tests/common
++logname=$AUTOPKGTEST_TMP/surfaces.txt
++(
++    get_files_with_surfaces | while read fn; do
++        echo $fn
++        mkdir -p $AUTOPKGTEST_TMP/$(dirname $fn)
++        solvespace-cli export-surfaces --output $AUTOPKGTEST_TMP/%_surfaces.step $fn
++    done
++) 2>&1 | tee $logname
++
++! grep "Error" $logname
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7adf97e0b29b7e05ec0c5d49cc038d4f2d10f63e
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++#!/bin/sh
++
++set -e
++set -x
++. debian/tests/common
++logname=$AUTOPKGTEST_TMP/thumbnail.txt
++(
++    get_files_to_thumbnail | while read fn; do
++        echo $fn
++        mkdir -p $AUTOPKGTEST_TMP/$(dirname $fn)
++        solvespace-cli thumbnail --output $AUTOPKGTEST_TMP/%_thumb.png --size 48x48 --view isometric $fn
++    done
++) 2>&1 | tee $logname
++
++# We don't care about self-intersecting errors.
++! grep "Error" $logname
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7f709cc5b2b32146f4b1f5fc9f26cf5d507253e9
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,14 @@@
++#!/bin/sh
++set -e
++set -x
++. debian/tests/common
++logname=$AUTOPKGTEST_TMP/view.txt
++(
++    get_all_files | while read fn; do
++        echo $fn
++        mkdir -p $AUTOPKGTEST_TMP/$(dirname $fn)
++        solvespace-cli export-view --output $AUTOPKGTEST_TMP/%_view.pdf --view isometric $fn
++    done
++) 2>&1 | tee $logname
++
++! grep "Error" $logname
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..15d520539f0a39c7cab1c7216a4dca0a7589438d
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,14 @@@
++#!/bin/sh
++set -e
++set -x
++. debian/tests/common
++logname=$AUTOPKGTEST_TMP/wireframe.txt
++(
++    get_all_files | while read fn; do
++        echo $fn
++        mkdir -p $AUTOPKGTEST_TMP/$(dirname $fn)
++        solvespace-cli export-wireframe --output $AUTOPKGTEST_TMP/%_wireframe.dxf $fn
++    done
++) 2>&1 | tee $logname
++
++! grep "Error" $logname
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4425fa5af91443cc102e3c8be2ef7173c064b988
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++Repository-Browse: https://github.com/solvespace/solvespace
++Repository: https://github.com/solvespace/solvespace.git
++Bug-Database: https://github.com/solvespace/solvespace/issues
++Bug-Submit: https://github.com/solvespace/solvespace/issues/new
diff --cc debian/watch
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..88dc9e76ff90f14e3a9ed67ec8bc5dea34363748
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,8 @@@
++version=4
++opts="\
++    repacksuffix=+ds1,\
++    uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|b|a)\d*)$/$1~$2/,\
++    dversionmangle=s/@DEB_EXT@//" \
++    https://github.com/solvespace/solvespace/releases \
++    .*/@PACKAGE@-v?(\d\S*)@ARCHIVE_EXT@
++