diff --git a/_config.yml b/_config.yml index 8a1ac743..82567104 100644 --- a/_config.yml +++ b/_config.yml @@ -77,5 +77,12 @@ exclude: [ 'vendor', ] +# Includes +include: [ + '_static', + '_sources', + '.doctrees' +] + # Extra Variables for the templates tagline: finds duplicate files diff --git a/_data/externallinks.yml b/_data/externallinks.yml new file mode 100644 index 00000000..3937f2ad --- /dev/null +++ b/_data/externallinks.yml @@ -0,0 +1,4 @@ +- title: Help + url: /help/en/ +- title: Github + url: https://github.com/hsoft/dupeguru/ \ No newline at end of file diff --git a/_includes/header.html b/_includes/header.html new file mode 100644 index 00000000..3f1a893a --- /dev/null +++ b/_includes/header.html @@ -0,0 +1,37 @@ + \ No newline at end of file diff --git a/about.md b/about.md new file mode 100644 index 00000000..d0808a8f --- /dev/null +++ b/about.md @@ -0,0 +1,14 @@ +--- +title: About +permalink: /about/ +--- + +[Issue Tracker](https://github.com/hsoft/dupeguru/issues) + +[Get Involved](https://www.hardcoded.net/dupeguru/help/en/contribute.html) + +[Linux Notes](https://www.hardcoded.net/linux_notes) + +[Changelog](https://www.hardcoded.net/dupeguru/help/en/changelog) + +[Screenshots?](https://www.hardcoded.net/dupeguru/screenshots) diff --git a/help/de/.buildinfo b/help/de/.buildinfo new file mode 100644 index 00000000..65efcb2b --- /dev/null +++ b/help/de/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 3a168d4db46680916131b91237a95198 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/help/de/.doctrees/changelog.doctree b/help/de/.doctrees/changelog.doctree new file mode 100644 index 00000000..b11b821e Binary files /dev/null and b/help/de/.doctrees/changelog.doctree differ diff --git a/help/de/.doctrees/environment.pickle b/help/de/.doctrees/environment.pickle new file mode 100644 index 00000000..39f03bd1 Binary files /dev/null and b/help/de/.doctrees/environment.pickle differ diff --git a/help/de/.doctrees/faq.doctree b/help/de/.doctrees/faq.doctree new file mode 100644 index 00000000..af0c5c81 Binary files /dev/null and b/help/de/.doctrees/faq.doctree differ diff --git a/help/de/.doctrees/folders.doctree b/help/de/.doctrees/folders.doctree new file mode 100644 index 00000000..5632c351 Binary files /dev/null and b/help/de/.doctrees/folders.doctree differ diff --git a/help/de/.doctrees/index.doctree b/help/de/.doctrees/index.doctree new file mode 100644 index 00000000..fa83e84f Binary files /dev/null and b/help/de/.doctrees/index.doctree differ diff --git a/help/de/.doctrees/preferences.doctree b/help/de/.doctrees/preferences.doctree new file mode 100644 index 00000000..d4ec1dc9 Binary files /dev/null and b/help/de/.doctrees/preferences.doctree differ diff --git a/help/de/.doctrees/quick_start.doctree b/help/de/.doctrees/quick_start.doctree new file mode 100644 index 00000000..30421534 Binary files /dev/null and b/help/de/.doctrees/quick_start.doctree differ diff --git a/help/de/.doctrees/reprioritize.doctree b/help/de/.doctrees/reprioritize.doctree new file mode 100644 index 00000000..db2e0dac Binary files /dev/null and b/help/de/.doctrees/reprioritize.doctree differ diff --git a/help/de/.doctrees/results.doctree b/help/de/.doctrees/results.doctree new file mode 100644 index 00000000..f0bca27b Binary files /dev/null and b/help/de/.doctrees/results.doctree differ diff --git a/help/de/_sources/changelog.rst.txt b/help/de/_sources/changelog.rst.txt new file mode 100644 index 00000000..b1fc6f65 --- /dev/null +++ b/help/de/_sources/changelog.rst.txt @@ -0,0 +1,705 @@ +:tocdepth: 1 + +Changelog +========= + +**About the word "crash":** When reading this changelog, you might be alarmed at the number of fixes +for "crashes". Be aware that when the word "crash" is used here, it refers to "soft crashes" which +don't cause the application to quit. You simply get an error window that asks you if you want to +send the crash report to Hardcoded Software. Crashes that cause the application to quit are called +"hard crashes" in this changelog. + + +4.0.3 (2016-11-24) +---------------------- + +* Add new picture cache backend: shelve +* Make shelve picture cache backend the active one on MacOS to fix `#394 `__ more + elegantly. [cocoa] +* Remove Sparkle (auto-updates) due to technical limitations. [cocoa] + + +4.0.2 (2016-10-09) +---------------------- + +* Fix systematic crash in Picture Mode under MacOS Sierra. (`#394 `__) +* No change for Linux. Just keeping version in sync. + + +4.0.1 (2016-08-24) +---------------------- + +* Add Greek localization, by Gabriel Koutilellis. (`#382 `__) +* Fix localization base path. [qt] (`#378 `__) +* Fix broken load results dialog. [qt] +* Fix crash on load results. [cocoa] (`#380 `__) +* Save preferences more predictably. [qt] (`#379 `__) +* Fix picture mode's fuzzy block scanner threshold. (`#387 `__) + + +4.0.0 (2016-07-01) +---------------------- + +* Merge Standard, Music and Picture editions in the same application! +* Improve documentation. (`#294 `__) +* Add Polish, Korean, Spanish and Dutch localizations. +* qt: Fix wrong use_regexp option propagation to core. (`#295 `__) +* qt: Fix progress window mistakenly showing up on startup. (`#357 `__) +* Bump Python requirement to v3.4. +* Bump OS X requirement to 10.8 +* Drop Windows support, maybe temporarily. + `Details `__-11-01>`_ +* cocoa: Drop iPhoto, Aperture and iTunes support. Was unmaintained and obsolete. +* Drop "Audio Contents" scan type. Was confusing and seldom useful. +* Change license to GPLv3 + + +3.9.1 (2014-10-17) +---------------------- + +* Fixed ``AttributeError: 'ComboboxModel' object has no attribute 'reset'``. [Linux, Windows] (`#254 `__) +* Fixed ``PermissionError`` on saving results. (`#266 `__) +* Fixed a build problem introduced by Sphinx 1.2.3. +* Updated German localisation, by Frank Weber. + + +3.9.0 (2014-04-19) +---------------------- + +* This is mostly a dependencies upgrade. +* Upgraded to Python 3.3. +* Upgraded to Qt 5. +* Minimum Windows version is now Windows 7 64bit. +* Minimum Ubuntu version is now 14.04. +* Minimum OS X version is now 10.7 (Lion). +* ... But with a couple of little improvements. +* Improved documentation. +* Overwrite subfolders' state when setting states in folder dialog (`#248 `__) +* The error report dialog now brings the user to Github issues. + + +3.8.0 (2013-12-07) +---------------------- + +* Disable symlink/hardlink deletion option when not relevant. (`#247 `__) +* Make Cmd+A select all folders in the Folder Selection dialog. [Mac] (`#228 `__) +* Make non-numeric delta comparison case insensitive. (`#239 `__) +* Fix surrogate-related UnicodeEncodeError on CSV export. (`#210 `__) +* Fixed crash on Dupe Count sorting with Delta + Dupes Only. (`#238 `__) +* Improved documentation. +* Important internal refactorings. +* Dropped Ubuntu 12.04 and 12.10 support. +* Removed the fairware dialog (`More Info `__). + + +3.7.1 (2013-08-19) +---------------------- + +* Fixed folder scan type, which was broken in v3.7.0. + + +3.7.0 (2013-08-17) +---------------------- + +* Improved delta values to support non-numerical values. (`#213 `__) +* Improved the Re-Prioritize dialog's UI. (`#224 `__) +* Added hardlink/symlink support on Windows Vista+. (`#220 `__) +* Dropped 32bit support on Mac OS X. +* Added Vietnamese localization by Phan Anh. + + +3.6.1 (2013-04-28) +---------------------- + +* Improved "Make Selection Reference" to make it clearer. (`#222 `__) +* Improved "Open Selected" to allow opening more than one file at once. (`#142 `__) +* Fixed a few typos here and there. (`#216 `__ `#225 `__) +* Tweaked the fairware dialog (`More Info `__). +* Added Arch Linux packaging +* Added a 64-bit build for Windows. +* Improved Russian localization by Kyrill Detinov. +* Improved Brazilian localization by Victor Figueiredo. + + +3.6.0 (2012-08-08) +---------------------- + +* Added "Export to CSV". (`#189 `__) +* Added "Replace with symlinks" to complement "Replace with hardlinks". [Mac, Linux] (`#194 `__) +* dupeGuru now tells how many duplicates were affected after each re-prioritization operation. (`#204 `__) +* Added Longest/Shortest filename criteria in the re-prioritize dialog. (`#198 `__) +* Fixed result table cells which mistakenly became writable in v3.5.0. [Mac] (`#203 `__) +* Fixed "Rename Selected" which was broken since v3.5.0. [Mac] (`#202 `__) +* Fixed a bug where "Reset to Defaults" in the Columns menu wouldn't refresh menu items' marked state. +* Added Brazilian localization by Victor Figueiredo. + + +3.5.0 (2012-06-01) +---------------------- + +* Added a Deletion Options panel. +* Greatly improved memory usage for big scans. +* Added a keybinding for the filter field. (`#182 `__) [Mac] +* Upgraded minimum requirements for Ubuntu to 12.04. + + +3.4.1 (2012-04-14) +---------------------- + +* Fixed the "Folders" scan type. [Mac] +* Fixed localization issues. [Windows, Linux] + + +3.4.0 (2012-03-29) +---------------------- + +* Improved results window UI. [Windows, Linux] +* Added a dialog to edit the Ignore List. +* Added the ability to sort results by "marked" status. +* Fixed "Open with default application". (`#190 `__) +* Fixed a bug where there would be a false reporting of discarded matches. (`#195 `__) +* Fixed various localization glitches. +* Fixed hard crashes on crash reporting. (`#196 `__) +* Fixed bug where the details panel would show up at inconvenient places in the screen. [Windows, Linux] + + +3.3.3 (2012-02-01) +---------------------- + +* Fixed crash on adding some folders. [Mac OS X] +* Added Ukrainian localization by Yuri Petrashko. + + +3.3.2 (2012-01-16) +---------------------- + +* Fixed random hard crashes (yeah, again). [Mac OS X] +* Fixed crash on Export to HTML. [Windows, Linux] +* Added Armenian localization by Hrant Ohanyan. +* Added Russian localization by Igor Pavlov. + + +3.3.1 (2011-12-02) +---------------------- + +* Fixed a couple of nasty crashes. + + +3.3.0 (2011-11-30) +---------------------- + +* Added multiple-selection in folder selection dialog for a more efficient folder removal. (`#179 `__) +* Fixed a crash in the prioritize dialog. (`#178 `__) +* Fixed a bug where mass marking with a filter would mark more than filtered duplicates. (`#181 `__) +* Fixed random hard crashes. [Mac OS X] (`#183 `__ `#184 `__) +* Added Czech localization by Aleš Nehyba. +* Added Italian localization by Paolo Rossi. + + +3.2.1 (2011-10-02) +---------------------- + +* Fixed a couple of broken action bindings from v3.2.0. + + +3.2.0 (2011-09-27) +---------------------- + +* Added duplicate re-prioritization dialog. (`#138 `__) +* Added font size preference for duplicate table. (`#82 `__) +* Added Quicklook support. [Mac OS X] (`#21 `__) +* Improved behavior of Mark Selected. (`#139 `__) +* Improved filename sorting. (`#169 `__) +* Added Chinese (Simplified) localization by Eric Dee. +* Tweaked the fairware system. +* Upgraded minimum requirements to OS X 10.6 and Ubuntu 11.04. + + +3.1.2 (2011-08-25) +---------------------- + +* Fixed a bug preventing the Folders scan from working. (`#172 `__) + + +3.1.1 (2011-08-24) +---------------------- + +* Added German localization by Gregor Tätzner. +* Improved OS X Lion compatibility. [Mac OS X] +* Made the file collection phase cancellable. (`#168 `__) +* Fixed glitch in folder window upon selecting a folder state. [Windows, Linux] (`#165 `__) +* Fixed a text coloring glitch in the results. (`#156 `__) +* Fixed glitch in the sorting feature of the Folder column. (`#161 `__) +* Make sure that saved results have the ".dupeguru" extension. [Linux] (`#157 `__) + + +3.1.0 (2011-04-16) +---------------------- + +* Added the "Folders" scan type. (`#89 `__) +* Fixed a couple of crashes. (`#140 `__ `#149 `__) + + +3.0.2 (2011-03-16) +---------------------- + +* Fixed crash after removing marked dupes. (`#140 `__) +* Fixed crash on error handling. [Windows] (`#144 `__) +* Fixed crash on copy/move. [Windows] (`#148 `__) +* Fixed crash when launching dupeGuru from a very long folder name. [Mac OS X] (`#119 `__) +* Fixed a refresh bug in directory panel. (`#153 `__) +* Improved reliability of the "Send to Trash" operation. [Linux] +* Tweaked Fairware reminders. + + +3.0.1 (2011-01-27) +---------------------- + +* Restored the context menu which had been broken in 3.0.0. [Mac OS X] (`#133 `__) +* Fixed a bug where an "unsaved results" warning would be issued on quit even with empty results. (`#134 `__) +* Removed focus from the cancel button in the progress dialog to avoid accidental cancellations. [Mac OS X] (`#135 `__) +* Folders added through drag and drop are added to the recent folders list. (`#136 `__) +* Added a debugging mode. (`#132 `__) +* Fixed french localization glitches. + + +3.0.0 (2011-01-24) +---------------------- + +* Re-designed the UI. (`#129 `__) +* Internationalized dupeGuru and localized it to french. (`#32 `__) +* Changed the format of the help file. (`#130 `__) + + +2.12.3 (2011-01-01) +---------------------- + +* Fixed bug causing results to be corrupted after a scan cancellation. (`#120 `__) +* Fixed crash when fetching Fairware unpaid hours. (`#121 `__) +* Fixed crash when replacing files with hardlinks. (`#122 `__) + + +2.12.2 (2010-10-05) +---------------------- + +* Fixed delta column colors which were broken since 2.12.0. +* Fixed column sorting crash. (`#108 `__) +* Fixed occasional crash during scan. (`#106 `__) + + +2.12.1 (2010-09-30) +---------------------- + +* Re-licensed dupeGuru to BSD and made it `Fairware `__. + + +2.12.0 (2010-09-26) +---------------------- + +* Improved UI with a little revamp. +* Added the possibility to place hardlinks to references after having deleted duplicates. [Mac OS X, Linux] (`#91 `__) +* Added an option to ignore duplicates hardlinking to the same file. [Mac OS X, Linux] (`#92 `__) +* Added multiple selection in the "Add Directory" dialog. [Mac OS X] (`#105 `__) +* Fixed a bug preventing drag & drop from working in the Directories panel. [Windows, Linux] + + +2.11.1 (2010-08-26) +---------------------- + +* Fixed HTML exporting which was broken in 2.11.0. + + +2.11.0 (2010-08-18) +---------------------- + +* Added the ability to save results (and reload them) at arbitrary locations. +* Improved the way reference files in dupe groups are chosen. (`#15 `__) +* Remember size/position of all windows between launches. (`#102 `__) +* Fixed a bug sometimes preventing dupeGuru from reloading previous results. +* Fixed a bug sometimes causing the progress dialog to be stuck there. [Mac OS X] (`#103 `__) +* Removed the Creation Date column, which wasn't displaying the correct value anyway. (`#101 `__) + + +2.10.1 (2010-07-15) +---------------------- + +* Fixed a couple of crashes. (`#95 `__, `#97 `__, `#100 `__) + + +2.10.0 (2010-04-13) +---------------------- + +* Improved error messages when files can't be sent to trash, moved or copied. +* Added a custom command invocation action. (`#12 `__) +* Filters are now applied on whole paths. (`#4 `__) + + +2.9.2 (2010-02-10) +---------------------- + +* dupeGuru is now 64-bit on Mac OS X! +* Fixed a crash upon quitting when support folder is not present. (`#83 `__) +* Fixed a crash during sorting. (`#85 `__) +* Fixed selection glitches, especially while renaming. (`#93 `__) + + +2.9.1 (2010-01-13) +---------------------- + +* Improved memory usage for Contents scans. (`#75 `__) +* Improved scanning speed when ref directories are involved. (`#77 `__) +* Show a message dialog at the end of the scan if no duplicates are found. (`#81 `__) +* Fixed a bug sometimes causing the small files threshold pref to be ignored. [Mac OS X] (`#75 `__) + + +2.9.0 (2009-11-03) +---------------------- + +* Significantly improved speed and memory usage of big contents-based scans. +* Added drag & drop support in the Directories panel. (`#9 `__) +* Fixed a bug causing dupeGuru to be confused if a scanned file was moved during the scan. (`#72 `__) +* Dropped support for Mac OS X 10.4 (Tiger) + + +2.8.2 (2009-10-14) +---------------------- + +* Improved directory selection in the Directories panel (Windows). (`#56 `__) +* Fixed a bug preventing dupeGuru from starting on certain machines (Windows). (`#68 `__) +* Fixed a crash during very big scans. (`#70 `__) + + +2.8.1 (2009-10-02) +---------------------- + +* Fixed crash with filtering when regular expressions were enabled. (`#60 `__) +* Fixed crash when setting directories' state. (Mac OS X) (`#66 `__) +* Fixed crash with Make Reference when certain filters are applied. (Mac OS X) (`#55 `__) +* Improved error handling during delete/move/copy actions. (`#62 `__ `#65 `__) + + +2.8.0 (2009-09-07) +---------------------- + +* Added support for all kinds of bundle (not just applications) (Mac OS X) (`#11 `__) +* Re-introduced the Export to XHTML feature to Windows. (`#14 `__) +* Improved Export to XHTML speed. (`#14 `__) +* Improved Contents scanning speed for large files. (`#33 `__) +* Improved the grouping algorithm to reduce the number of discarded files in non-exact scans. (`#51 `__) +* Stopped showing the same file on the 2 sides of the details panel when a ref file is selected. (`#50 `__) +* Fixed crashes in the Directories panel. (`#46 `__) + + +2.7.3 (2009-06-20) +---------------------- + +* Fixed bugs with selection being jumpy during "Make Reference" actions and Power Marker + switches. (`#3 `__) +* Fixed crash happening when a file with non-roman characters couldn't be analyzed. (`#30 `__) +* Fixed crash sometimes happening during the file collection phase in scanning. (`#38 `__) +* Restored double-click and right-click behavior lost in the PyQt move (Windows). (`#34 `__ `#35 `__) + + +2.7.2 (2009-06-10) +---------------------- + +* Fixed an occasional crash on Copy/Move operations. (`#16 `__) +* Added automatic exclusion for sensible folders (like system folders). (`#20 `__) +* Fixed an occasional crash when application files were part of the results (Mac OS X). (`#25 `__) + + +2.7.1 (2009-05-29) +---------------------- + +* Fixed a bug causing crashes when having application files in the results. +* Fixed a bug causing a GUI freeze at the beginning of a scan with a lot of files. +* Fixed a bug that sometimes caused a crash when an action was cancelled, and then started again. + + +2.7.0 (2009-05-25) +---------------------- + +* Converted the Windows GUI to Qt. +* Improved the reliability of the scanning process. + + +2.6.1 (2009-03-27) +---------------------- + +* **Fixed** an occasional crash caused by permission issues. +* **Fixed** a bug where the "X discarded" notice would show a too large number of discarded + duplicates. + + +2.6.0 (2008-09-10) +---------------------- + +* **Added** a small file threshold preference. +* **Added** a notice in the status bar when matches were discarded during the scan. +* **Improved** duplicate prioritization (smartly chooses which file you will keep). +* **Improved** scan progress feedback. +* **Improved** responsiveness of the user interface for certain actions. + + +2.5.4 (2008-08-10) +---------------------- + +* **Improved** the speed of results loading and saving. +* **Fixed** a crash sometimes occurring during duplicate deletion. + + +2.5.3 (2008-07-08) +---------------------- + +* **Improved** unicode handling for filenames. dupeGuru will now find a lot more duplicates if your files have non-ascii characters in it. +* **Fixed** "Clear Ignore List" crash in Windows. + + +2.5.2 (2008-01-10) +---------------------- + +* **Improved** the handling of low memory situations. +* **Improved** the directory panel. The "Remove" button changes to "Put Back" when an excluded directory is selected. +* **Improved** scan, delete and move speed in situations where there were a lot of duplicates. +* **Fixed** occasional crashes when moving bundles (such as .app files). +* **Fixed** occasional crashes when moving a lot of files at once. + + +2.5.1 (2007-11-22) +---------------------- + +* **Added** the "Remove empty folders" option. +* **Fixed** results load/save issues. +* **Fixed** occasional status bar inaccuracies when the results are filtered. + + +2.5.0 (2007-09-15) +---------------------- + +* **Added** post scan filtering. +* **Fixed** issues with the rename feature under Windows +* **Fixed** some user interface annoyances under Windows + + +2.4.8 (2007-04-14) +---------------------- + +* **Improved** UI responsiveness (using threads) under Mac OS X. +* **Improved** result load/save speed and memory usage. + + +2.4.7 (2007-03-10) +---------------------- + +* **Fixed** a "bad file descriptor" error occasionally popping up. +* **Fixed** a bug with non-latin directory names. + + +2.4.6 (2007-02-10) +---------------------- + +* **Added** Re-orderable columns. In fact, I re-added the feature which was lost in the C# conversion in 2.4.0 (Windows). +* **Changed** the behavior of the scanning engine when setting the hardness to 100. It will now only match files that have their words in the same order. +* **Fixed** a bug with all the Delete/Move/Copy actions with certain kinds of files. + + +2.4.5 (2007-01-11) +---------------------- + +* **Fixed** a bug with the Move action. + + +2.4.4 (2007-01-07) +---------------------- + +* **Fixed** a "ghosting" bug. Dupes deleted by dupeGuru would sometimes come back in subsequent scans (Windows). +* **Fixed** bugs sometimes making dupeGuru crash when marking a dupe (Windows). +* **Fixed** some minor visual glitches (Windows). + + +2.4.3 (2006-12-08) +---------------------- + +* **Fixed** a mishandling of ".app" files (OS X). +* **Fixed** a bug preventing files from "reference" directories to be displayed in blue in the results (Windows). +* **Fixed** a bug preventing some files to be sent to the recycle bin (Windows). +* **Fixed** a bug in the packaging preventing certain Windows configurations to start dupeGuru at all. + + +2.4.2 (2006-11-18) +---------------------- + +* **Fixed** a bug with directory states. + + +2.4.1 (2006-11-15) +---------------------- + +* **Fixed** a bug causing the ignore list not to be saved. +* **Fixed** a bug sometimes making delete and move operations stall. + + +2.4.0 (2006-11-10) +---------------------- + +* **Changed** the Windows interface. It is now .NET based. +* **Added** an auto-update feature to the windows version. +* **Changed** the way power marking works. It is now a mode instead of a separate window. +* **Changed** the "Size (MB)" column for a "Size (KB)" column. The values are now "ceiled" instead of rounded. Therefore, a size "0" is now really 0 bytes, not just a value too small to be rounded up. It is also the case for delta values. +* **Removed** the min word length/count options. These came from Mp3 Filter, and just aren't used anymore. Word weighting does pretty much the same job. + + +2.3.4 (2006-11-07) +---------------------- + +* **Improved** speed and memory usage of the scanning engine, again. Does it mean there was a lot of improvements to be made? Nah... + + +2.3.3 (2006-11-02) +---------------------- + +* **Improved** speed and memory usage of the scanning engine, especially when the scan results in a lot of duplicates. +* Now I wonder if Sparkle is going to work well... + + +2.3.2 (2006-10-16) +---------------------- + +* **Added** an auto-update feature in the Mac OS X version (with Sparkle). +* **Fixed** a bug preventing some duplicate reports to be created correctly under Windows. + + +2.3.1 (2006-10-02) +---------------------- + +* **Fixed** a bug preventing some duplicates to be found, especially when scanning lots of files. + + +2.3.0 (2006-09-22) +---------------------- + +* **Added** XHTML export feature. + + +2.2.10 (2006-08-31) +---------------------- + +* **Added** sticky columns. +* **Fixed** an issue with file caching between scans. +* **Fixed** an issue preventing some duplicates from being deleted/moved/copied. + + +2.2.9 (2006-08-27) +---------------------- + +* **Fixed** an issue with ignore list and unicode. +* **Fixed** an issue with file attribute fetching sometimes causing dupeGuru to crash. +* **Fixed** an issue in the directories panel under Windows. + + +2.2.8 (2006-08-17) +---------------------- + +* **Fixed** an issue in the duplicate seeking engine preventing some duplicates to be found. + + +2.2.7 (2006-08-12) +---------------------- + +* **Improved** unicode support. +* **Improved** the "Reveal in Finder" ("Open Containing Folder" in Windows) feature so it selects the file in the folder it opens. + + +2.2.6 (2006-08-07) +---------------------- + +* **Improved** the ignore list system. +* dupeGuru is now a Universal application on Mac OS X. + + +2.2.5 (2006-07-26) +---------------------- + +* **Improved** application (.app) dupe detection on Mac OS X. +* **Fixed** an issue that occasionally made dupeGuru crash on startup. + + +2.2.4 (2006-06-27) +---------------------- + +* **Fixed** an issue with Move and Copy features. + + +2.2.3 (2006-06-15) +---------------------- + +* **Improved** duplicate scanning speed. +* **Added** a warning that a file couldn't be renamed if a file with the same name already exists. + + +2.2.2 (2006-06-07) +---------------------- + +* **Added** "Rename Selected" feature. +* **Fixed** some minor issues with "Reload Last Results" feature. +* **Fixed** ignore list issues. + + +2.2.1 (2006-05-22) +---------------------- + +* **Fixed** occasional progress bar woes under Windows. +* **Fixed** a bug in the registration system under Windows. +* Nothing has been changed in the Mac OS X version, but I want to keep version in sync. + + +2.2.0 (2006-05-10) +---------------------- + +* **Added** destination path re-creation options. +* **Added** an ignore list. +* **Changed** the main icon. +* **Improved** dramatically the delta values feature. + + +2.1.2 (2006-04-18) +---------------------- + +* **Added** the "Match similar words" option. +* **Fixed** Power marking issues under Mac. + + +2.1.1 (2006-04-14) +---------------------- + +* **Added** the "Display delta values" option. +* **Improved** Power marking sorting speed under Mac. +* **Fixed** Power marking sorting issues. + + +2.1.0 (2006-04-03) +---------------------- + +* **Added** the Power Marker feature. +* **Fixed** a column sorting bug. The results would sometimes lose their sort order. +* **Fixed** a bug with the Make Reference feature. The results sometimes wasn't correctly refreshed after the reference switch. + + +2.0.1 (2006-03-23) +---------------------- + +* **Fixed** an issue occasionally occurring when trying to reload results from removable media that is no longer present. + + +2.0.0 (2006-03-17) +---------------------- + +* Complete rewrite. +* Now runs on Mac OS X. + + +1.0.0 (2004-09-24) +---------------------- + +* Initial release. + diff --git a/help/de/_sources/faq.rst.txt b/help/de/_sources/faq.rst.txt new file mode 100644 index 00000000..57c32969 --- /dev/null +++ b/help/de/_sources/faq.rst.txt @@ -0,0 +1,115 @@ +Häufig gestellte Fragen +========================== + +.. topic:: What is dupeGuru? + + .. only:: edition_se + + DupeGuru ist ein Tool zum Auffinden von Duplikaten auf Ihrem Computer. Es kann entweder Dateinamen oder Inhalte scannen. Der Dateiname-Scan stellt einen lockeren Suchalgorithmus zur Verfügung, der sogar Duplikate findet, die nicht den exakten selben Namen haben. + + .. only:: edition_me + + dupeGuru Music Edition ist ein Tool zum Auffinden von Duplikaten in Ihrer Musiksammlung. Es kann seine Suche auf Dateinamen, Tags oder Inhalte basieren. Der Dateiname-Scan und Tag-Scan stellt einen lockeren Suchalgorithmus zur Verfügung, der sogar Dateinamen und Tags findet, die nicht den exakt selben Namen haben. + + .. only:: edition_pe + + dupeGuru Picture Edition (kurz PE) ist ein Tool zum Auffinden von doppelten Bildern auf Ihrem Computer. Es findet nicht nur exakte Übereinstimmungen, sondern auch Duplikate unterschiedlichen Dateityps (PNG, JPG, GIF etc..) und Qualität. + +.. topic:: Was macht es besser ala andere Duplikatscanner? + + Die Scan-Engine ist extrem flexibel. Sie können sie modifizieren, um die Art von Ergebnissen zu bekommen die Sie möchten. Sie können mehr über die dupeGuru Modifikationen finden auf der :doc:`Einstellungen Seite `. + +.. topic:: Wie sicher ist dupeGuru? + + Sehr sicher. DupeGuru wurde entwickelt, um sicherzustellen keine Dateien zu löschen, die nicht gelöscht werden sollen. Erstens, es existiert ein Referenzordnersystem welches Ordner definiert, die auf **keinen** Fall angefasst werden sollen. Dann gibt es noch das Referenzgruppensystem, das sicherstellt das **immer** ein Mitglied einer Duplikatgruppe behalten wird. + +.. topic:: Was sind die Demo-Einschränkungen von dupeGuru? + + Keine, dupeGuru ist `Fairware `_. + +.. topic:: Die Markierungsbox einer Datei, die ich löschen möchte, ist deaktiviert. Was muss ich tun? + + Sie können die Referenz nicht markieren (die erste Datei einer Duplikatgruppe). Wie auch immer, Sie können ein Duplikat zur Referenz befördnern. Wenn eine Datei, die Sie markieren möchten, eine Referenz ist, muss ein Duplikat der Gruppe zur Referenz gemacht werden, indem man es auswählt und auf **Aktionen-->Mache Ausgewählte zur Referenz** gehen. Befindet sich die Referenzdatei in einem Referenzordner (Dateiname in blauen Buchstaben), kann sie nicht aus der Referenzposition entfernt werden. + +.. topic:: ich habe einen Ordner aus dem ich wirklich nichts löschen möchte. + + Möchten Sie sicherstellen, das dupeGuru niemals Dateien aus einem bestimmten Ordner löscht, dann versetzen sie den Ordner in den **Referenzzustand**. Siehe :doc:`folders`. + +.. topic:: Was bedeutet diese '(X verworfen)' Nachricht in der Statusbar? + + In einigen Fällen werden manche Treffer aus Sicherheitsgründen nicht in den Ergebnissen angezeigt. Lassen Sie mich ein Beispiel konstruieren. Wir haben 3 Datein: A, B und C. Wir scannen sie mit einer niedrigen Filterempfindlichkeit. Der Scanner findet heraus das A mit B und C übereinstimmt, aber B **nicht** mit C übereinstimmt. Hier hat dupeGuru ein Problem. Es kann keine Duplikatgruppe erstellen mit A, B und C, weil nicht alle Dateien der Gruppe zusammenpassen. Es könnte 2 Gruppen erstellen: eine A-B Gruppe und eine A-C Gruppe, aber es dies aus Sicherheitsbedenken nicht tun. Denken wir darüber nach: Wenn B nicht zu C passt, heißt das, das entweder B oder C keine echten Duplikate sind. Wären es 2 Gruppen (A-B und A-C), würden Sie damit enden sowohl B als auch C zu löschen. Und ist keine der Beiden ein Duplikat, möchten Sie das ganz sicher nicht tun, richtig? Also verwirft dupeGuru in diesem Fall den A-C Treffer (und fügt eine Notiz in der Statusbar hinzu). Folglich, wenn Sie B löschen und den Scan erneut durchführen, haben Sie einen A-C Treffer nächstes Mal in den Ergebnissen. + +.. topic:: Ich möchte alle Dateien aus einem bestimmten Ordner markieren. Was kann ich tun? + + Aktiveren Sie den :doc:`Nur Duplikate ` Modus und klicken auf die Ordnerspalte, um die Duplikate nach Ordner zu sortieren. Es wird dann einfach sein, alle Duplikate aus dem selben Ordner auszuwählen und auf die Leertaste zu drücken, um sie alle zu markieren. + +.. only:: edition_se or edition_pe + + .. topic:: Ich möchte alle Dateien löschen, deren Größe sich um mehr als 300 KB von ihrer Referenz unterscheidet. Was kann ich tun? + + * Aktivieren Sie den :doc:`Nur Duplikate ` Modus. + * Aktivieren Sie den **Deltawerte** Modus. + * Gehen Sie auf die "Größe" Spalte, um die Ergebnisse nach Größe zu sortieren. + * Alle Duplikate unter -300 auswählen. + * Klicken Sie auf **Entferne Ausgewählte von den Ergebnissen**. + * Alle Duplikate über 300 auswählen + * Klicken Sie auf **Entferne Ausgewählte von den Ergebnissen**. + + .. topic:: Ich möchte meine zuletzt geänderten Dateien zur Referenz machen. Was kann ich tun? + + * Aktivieren Sie den :doc:`Nur Duplikate ` Modus. + * Aktivieren Sie den **Deltawerte** Modus. + * Gehen Sie auf die "Modifikation" Spalte, um die Ergebnisse nach Änderungsdatum zu sortieren. + * Klicken Sie erneut auf die "Modifikation" Spalte, um die Reihenfolge umzukehren. + * Wählen Sie alle Duplikate über 0. + * Klicken Sie auf **Mache Ausgewählte zur Referenz**. + + .. topic:: Ich möchte alle Duplikate mit dem Wort copy markieren. Wie mache ich das? + + * **Windows**: Klicken Sie auf **Aktionen --> Filter anwenden**, tippen "copy" und klicken auf OK. + * **Mac OS X**: Geben Sie "copy" in das "Filter" Feld in der Werkzeugleiste ein. + * Klicken Sie **Markieren --> Alle Markieren**. + +.. only:: edition_me + + .. topic:: Ich möchte alle Stücke markieren, die mehr als 3 Sekunden von ihrer Referenz verschieden sind. Was kann ich tun? + + * Aktivieren Sie den :doc:`Nur Duplikate ` Modus. + * Aktivieren Sie den **Deltawerte** Modus. + * Klicken Sie auf die "Zeit" Spalte, um nach Zeit zu sortieren. + * Wählen Sie alle Duplikate unter -00:03. + * Klicken Sie auf **Entferne Ausgewählte von den Ergebnissen**. + * Wählen Sie alle Duplikate über 00:03. + * Klicken Sie auf **Entferne Ausgewählte von den Ergebnissen**. + + .. topic:: Ich möchte meine Stücke mit der höchsten Bitrate zur Referenz machen. Was kann ich tun? + + * Aktivieren Sie den :doc:`Nur Duplikate ` Modus. + * Aktivieren Sie den **Deltawerte** Modus. + * Klicken Sie auf die "Bitrate" Spalte, um nach Bitrate zu sortieren. + * Klicken Sie erneut auf die "Bitrate" Spalte, um die Reihenfolge umzukehren. + * Wählen Sie alle Duplikate über 0. + * Klicken Sie auf **Mache Ausgewählte zur Referenz**. + + .. topic:: Ich möchte nicht das [live] und [remix] Versionen meiner Stücke als Duplikate erkannt werden. Was kann ich tun? + + Ist Ihre Vergleichsschwelle niedrig genug, werden möglicherweise die live und remix Versionen in der Ergebnisliste landen. Das kann nicht verhindert werden, aber es gibt die Möglichkeit die Ergebnisse nach dem Scan zu entfernen, mittels dem Filter. Möchten Sie jedes Stück mit irgendetwas in eckigen Klammern [] im Dateinamen entfernen, so: + + * **Windows**: Klicken Sie auf **Aktionen --> Filter anwenden**, geben "[*]" ein und klicken OK. + * **Mac OS X**: Geben Sie "[*]" in das "Filter" Feld der Werkzeugleiste ein. + * Klicken Sie auf **Markieren --> Alle Markieren**. + * Klicken Sie auf **Entferne Ausgewählte von den Ergebnissen**. + +.. topic:: Ich habe versucht, meine Duplikate in den Mülleimer zu verschieben, aber dupeGuru sagt es ist nicht möglich. Warum? Was kann ich tun? + + Meistens kann dupeGuru aufgrund von Dateirechten keine Dateien in den Mülleimer schicken. Sie brauchen **Schreib** Rechte für Dateien, die in den Mülleimer sollen. Wenn Sie nicht vertraut mit Kommandozeilenwerkzeugen sind, können dafür auch Dienstprogramme wie `BatChmod `_ verwendet werden, um die Dateirechte zu reparieren. + + Wenn dupeGuru sich nach dem Reparieren der Recht immer noch verweigert, könnte es helfen die Funktion "Verschiebe Markierte nach..." als Workaround zu verwenden. Anstelle die Dateien in den Mülleimer zu schieben, senden SIe sie in einen temporären Ordner, den Sie dann manuell löschen können. + + .. only:: edition_pe + + Wenn Sie versuchen *iPhoto* Bilder zu löschen, dann ist der Grund des Versagens ein Anderer. Das Löschen schlägt fehl, weil dupeGuru nicht mit iPhoto kommunizieren kann. Achten Sie darauf nicht mit iPhoto herumzuspielen, während dupeGuru arbeitet, damit das Löschen funktioniert. Außerdem scheint das Applescript System manchmal zu vergessen wo sich iPhoto befindet, um es zu starten. Es hilft in diesen Fällen, wenn Sie iPhoto starten **bevor** Duplikate in den Mülleimer verschoben werden. + + Wenn dies alles fehlschlägt, kontaktieren Sie `HS support `_, wir werden das Problem lösen. + +.. todo:: This FAQ qestion is outdated, see english version. diff --git a/help/de/_sources/folders.rst.txt b/help/de/_sources/folders.rst.txt new file mode 100644 index 00000000..22103b24 --- /dev/null +++ b/help/de/_sources/folders.rst.txt @@ -0,0 +1,23 @@ +Ordnerauswahl +================ + +Das erste Fenster das Sie sehen, wenn dupeGuru gestartet wird, ist das Ordnerauswahl Fenster. Dieses Fenster enthält die Liste der Ordner die durchsucht werden, wenn Sie **Scan** wählen. + +Das Fenster ist leicht zu bedienen. Wollen Sie einen Ordner hinzufügen, klicken Sie auf den **+** Knopf. Haben Sie bereits vorher Ordner hinzugefügt, erscheint ein Popup-Menü mit einer Liste der zuletzt hinzugefügten Ordner. Sie können einen davon auswählen, indem Sie darauf klicken. Wenn Sie auf den ersten Eintrag der Liste klicken, **Neuen Ordner hinzufügen...**, werden Sie nach einem Ordner zum Hinzufügen gefragt. Nutzen Sie dupeGuru zum ersten Mal, erscheint kein Menü und Sie werden direkt nach einem Ordner gefragt. Ein alternativer Weg zum Hinzufügen der Ordner ist, sie auf die Liste zu ziehen. + +Um einen Ordner zu entfernen, wählen Sie ihn aus und klicken auf **-**. Wenn Sie einen Unterordner auswählen, wird der ausgewählte Ordner in den **Ausgeschlossen** Zustand versetzt (siehe unten), anstatt entfernt zu werden. + +Ordnerzustände +-------------- + +Jeder Ordner kann in einem von 3 Zuständen sein: + +* **Normal:** Duplikate in diesem Ordner können gelöscht werden. +* **Referenz:** Duplikate in diesem Ordner können **nicht** gelöscht werden. Dateien dieses Ordners können sich nur in der **Referenz** Position einer Duplikatgruppe befinden. Ist mehr als eine Datei des Referenzordners in derselben Duplikatgruppe, so wird nur Eine behalten. Die Anderen werden aus der Gruppe entfernt. +* **Ausgeschlossen:** Dateien in diesem Verzeichnis sind nicht im Scan eingeschlossen. + +Der Standardzustand eines Ordners ist natürlich **Normal**. Sie können den **Referenz** Zustand für Ordner nutzen, in denen auf keinen Fall eine Datei gelöscht werden soll. + +Wenn sie einen Zustand für ein Verzeichnis setzen, erben alle Unterordner automatisch diesen Zustand, es sei denn Sie ändern den Zustand der Unterordner explizit. + +.. todo:: Add iPhoto/Aperture/iTunes libraries notes diff --git a/help/de/_sources/index.rst.txt b/help/de/_sources/index.rst.txt new file mode 100644 index 00000000..0ff217f3 --- /dev/null +++ b/help/de/_sources/index.rst.txt @@ -0,0 +1,47 @@ +dupeGuru Hilfe +=============== + +.. only:: edition_se + + Dieses Dokument ist auch auf `Englisch `__ und `Französisch `__ verfügbar. + +.. only:: edition_me + + Dieses Dokument ist auch auf `Englisch `__ und `Französisch `__ verfügbar. + +.. only:: edition_pe + + Dieses Dokument ist auch auf `Englisch `__ und `Französisch `__ verfügbar. + +.. only:: edition_se or edition_me + + dupeGuru ist ein Tool zum Auffinden von Duplikaten auf Ihrem Computer. Es kann entweder Dateinamen oder Inhalte scannen. Der Dateiname-Scan stellt einen lockeren Suchalgorithmus zur Verfügung, der sogar Duplikate findet, die nicht den exakten selben Namen haben. + +.. only:: edition_pe + + dupeGuru Picture Edition (kurz PE) ist ein Tool zum Auffinden von doppelten Bildern auf Ihrem Computer. Es findet nicht nur exakte Übereinstimmungen, sondern auch Duplikate unterschiedlichen Dateityps (PNG, JPG, GIF etc..) und Qualität. + +Obwohl dupeGuru auch leicht ohne Dokumentation genutzt werden kann, ist es sinnvoll die Hilfe zu lesen. Wenn Sie nach einer Führung für den ersten Duplikatscan suchen, werfen Sie einen Blick auf die :doc:`Schnellstart ` Sektion + +Es ist eine gute Idee dupeGuru aktuell zu halten. Sie können die neueste Version auf der `homepage`_ finden. + +Inhalte: + +.. toctree:: + :maxdepth: 2 + + quick_start + folders + preferences + results + reprioritize + faq + changelog + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` + +.. _homepage: https://www.hardcoded.net/dupeguru \ No newline at end of file diff --git a/help/de/_sources/preferences.rst.txt b/help/de/_sources/preferences.rst.txt new file mode 100644 index 00000000..301261b4 --- /dev/null +++ b/help/de/_sources/preferences.rst.txt @@ -0,0 +1,63 @@ +Einstellungen +============= + +.. only:: edition_se + + **Scan Typ:** Diese Option bestimmt nach welcher Eigenschaft die Dateien in einem Duplikate Scan verglichen werden. Wenn Sie **Dateiname** auswählen, wird dupeGuru jeden Dateinamen Wort für Wort vergleichen und, abhängig von den unteren Einstellungen, feststellen ob genügend Wörter übereinstimmen, um 2 Dateien als Duplikate zu betrachten. Wenn Sie **Inhalt** wählen, werden nur Dateien mit dem exakt gleichen Inhalt zusammenpassen. + + Der **Ordner** Scan Typ ist etwas speziell. Wird er ausgewählt, scannt dupeGuru nach doppelten Ordnern anstelle von Dateien. Um festzustellen ob 2 Ordner identisch sind, werden alle Datein im Ordner gescannt und wenn die Inhalte aller Dateien der Ordner übereinstimmen, werden die Ordner als Duplikate erkannt. + + **Filterempfindlichkeit:** Wenn Sie den **Dateiname** Scan Typ wählen, bestimmt diese Option wie ähnlich 2 Dateinamen für dupeGuru sein müssen, um Duplikate zu sein. Ist die Empfindlichkeit zum Beispiel 80, müssen 80% der Worte der 2 Dateinamen übereinstimmen. Um den Übereinstimmungsanteil herauszufinden, zählt dupeGuru zuerst die Gesamtzahl der Wörter **beider** Dateinamen, dann werden die gleichen Wörter gezählt (jedes Wort zählt als 2) und durch die Gesamtzahl der Wörter dividiert. Ist das Resultat größer oder gleich der Filterempfindlichkeit, haben wir ein Duplikat. Zum Beispiel, "a b c d" und "c d e" haben einen Übereinstimmungsanteil von 57 (4 gleiche Wörter, insgesamt 7 Wörter). + +.. only:: edition_me + + **Scan Typ:** Diese Option bestimmt nach welcher Eigenschaft die Dateien in einem Duplikate Scan verglichen werden. Die Beschaffenheit des Duplikate Scans hängt hauptsächlich davon ab, was Sie für diese Option auswählen. + + * **Dateiname:** Der Dateiname jedes Stücks wird in einzelne Wörter zerlegt und verglichen, um den Übereinstimmungsanteil zu berechnen. Ist das Resultat größer oder gleich der **Filterempfindlichkeit** (siehe unten für mehr Details), wird dupeGuru die beiden Stücke als Duplikate erkennen. + * **Dateiname - Felder:** Wie **Dateiname**, außer das, nachdem der Dateiname in Wörter geteilt wurde, diese Wörter in Felder gruppiert werden. Der Feldseparator ist " - ". Der endgültige Übereinstimmungsanteil ist der kleinste Übereinstimmungssatz zwischen den Feldern. Also, "Ein Künstler - Der Titel" und "Ein Künstler - Anderer Titel" hätte eine Übereinstimmung von 50 (Bei einem **Dateiname** Scan wäre es 75). + * **Dateiname - Felder (keine Reihenfolge):** Wie **Dateiname - Felder**, außer das die Feldreihenfolge keine Rolle spielt. Also, "Ein Künstler - Der Titel" und "Der Titel - Ein Künstler" hätte eine Übereinstimmung von 100 anstelle von 0. + * **Tags:** Diese Methode liest die Tags (Metadaten) jedes Stücks und vergleicht ihre Werte. Es wird, wie in **Dateiname - Felder**, die niedrigste Übereinstimmung als endgültiger Übereinstimmungsanteil betrachtet. + * **Inhalt:** Diese Scanmethode nutzt den Inhalt des Stücks, um Duplikate zu erkennen. Damit 2 Stücke mit dieser Methode gleich sind, müssen sie **exakt den selben Inhalt** haben. + * **Audioinhalt:** Das selbe wie Inhalt, aber nur der Audioinhalt wird verglichen (ohne Metadaten). + + **Filterempfindlichkeit:** Wenn Sie den **Dateiname** Scan Typ wählen, bestimmt diese Option wie ähnlich 2 Dateinamen für dupeGuru sein müssen, um Duplikate zu sein. Ist die Empfindlichkeit zum Beispiel 80, müssen 80% der Worte der 2 Dateinamen übereinstimmen. Um den Übereinstimmungsanteil herauszufinden, zählt dupeGuru zuerst die Gesamtzahl der Wörter **beider** Dateinamen, dann werden die gleichen Wörter gezählt (jedes Wort zählt als 2) und durch die Gesamtzahl der Wörter dividiert. Ist das Resultat größer oder gleich der Filterempfindlichkeit, haben wir ein Duplikat. Zum Beispiel, "a b c d" und "c d e" haben einen Übereinstimmungsanteil von 57% (4 gleiche Wörter, insgesamt 7 Wörter). + + **Tags zu scannen:** Bei der Nutzung des **Tags** Scan Typs, können Sie wählen welche Tags verglichen werden sollen. + +.. only:: edition_se or edition_me + + **Wortgewichtung:** Wenn Sie den **Dateiname** Scan Type nutzen, ändert diese Option leicht die Berechnung der Übereinstimmung. Mit Wortgewichtung hat jedes Wort nicht mehr den Wert 1 in der Duplikatezählung und der Gesamtwortzahl, sondern einen Wert der sich aus der Gesamtzahl der Buchstaben des Wortes ergibt. Mit Wortgewichtung hätte "ab cde fghi" und "ab cde fghij" eine Übereinstimmung von 53% (Gesamt 19 Buchstaben, 10 gleiche Buchstaben (4 für "ab" und 6 für "cde")). + + **Ähnliche Wörter gleich** Wird diese Option angeschaltet, zählen ähnliche Wörter als Übereinstimmung. Zum Beispiel hätte mit dieser Option "The White Stripes" und "The White Stripe" eine Übereinstimmung von 100 anstelle von 0. **Warnung:** Nutzen Sie diese Option mit Vorsicht. Es ist wahrscheinlich, das sie eine hohe Anzahl an Falschpositiven erhalten. Wie auch immer, Sie werden Duplikate finden, die Sie sonst nie gefunden hätten. Der Suchdurchlauf wird außerdem mit dieser Option etwas länger dauern. + +.. only:: edition_pe + + **Scan Typ:** Diese option bestimmt, welcher Scan Typ bei Ihren Bildern angewendet wird. Der **Inhalte** Scan Typ vergleicht den Inhalt der Bilder auf eine ungenaue Art und Weise (so werden nicht nur exakte Duplikate gefunden, sondern auch Ähnliche). Der **EXIF Zeitstempel** Scan Typ schaut auf die EXIF Metadaten der Bilder (wenn vorhanden) und erkennt Bilder die den Selben haben. Er ist viel schneller als der Inhalte Scan. **Warnung:** Veränderte Bilder behalten oft den selben EXIF Zeitstempel, also achten Sie auf Falschpositive bei der Nutzung dieses Scans. + + **Filterempfindlichkeit:** *Nur Inhalte Scan.* Je höher diese Einstellung, desto strenger ist der Filter (Mit anderen Worten, desto weniger Ergebnisse erhalten Sie). Die meisten Bilder der selben Qualität stimmen zu 100% überein, selbst wenn das Format anders ist (PNG und JPG zum Beispiel). Wie auch immer, wenn ein PNG mit einem JPG niederiger Qualität übereinstimmen soll, muss die Filterempfindlichkeit kleiner als 100 sein. Die Voreinstellung, 95, ist eine gute Wahl. + + **Bilder unterschiedlicher Abmessung gleich:** Wird diese Box gewählt, dürfen Bilder unterschiedlicher Abmessung in einer Duplikategruppe sein.. + +**Dateitypen dürfen gemischt werden:** Wird diese Box gewählt, dürfen Duplikategruppen Bilder mit unterschiedlichen Dateierweiterungen enthalten. + +**Ignoriere Duplikate die mit derselben Datei verlinkt sind:** Ist diese Option aktiviert, wird dupeGuru überprüfen ob Duplikate auf den selben `inode `_ verweisen. Wenn sie es tun, werden sie nicht als Duplikat erkannt. (Nur für OS X und Linux) + +**Nutze reguläre Ausdrücke beim Filtern:** Ist diese Option aktiviert, wird die Filterfunktion Ihre Filteranfrage als **regulären Ausdruck** interpretieren. Sie zu erklären ist außerhalb des Aufgabenbereiches dieser Dokumentation. Ein guter Platz zum Starten ist `regular-expressions.info `_. + +**Entferne leere Ordner nach dem Löschen oder Verschieben:** Ist diese Option aktiviert, werden Ordner gelöscht nachdem eine Datei gelöscht oder verschoben wurde und der Ordner leer ist. + +**Copy and Move:** Determines how the Copy and Move operations (in the Action menu) will behave. + +* **Zum Ziel:** Alle Dateien werden direkt in das ausgwählte Verzeichnis gesendet, ohne zu versuchen den Quellpfad wiederherzustellen +* **Relativen Pfad neu erstellen:** Der Pfad der Quelldatei wird im Zielverzeichnis wiederhergestellt bis zur Wurzelauswahl im Verzeichnis Panel. Zum Beispiel, wenn Sie ``/Users/foobar/SomeFolder`` zu ihrem Verzeichnis Panel hinzufügen und ``/Users/foobar/SomeFolder/SubFolder/SomeFile.ext`` zu dem Ziel ``/Users/foobar/MyDestination`` verschieben, wird das endgültige Ziel der Datei ``/Users/foobar/MyDestination/SubFolder`` sein (``SomeFolder`` wurde vom Pfad der Quelldatei im endgültigen Ziel abgetrennt.). +* **Absoluten Pfad neu erstellen:** Der Pfad der Quelldatei wird im Zielverzeichnis vollständig wiederhergestellt. Zum Beispiel, wenn Sie ``/Users/foobar/SomeFolder/SubFolder/SomeFile.ext`` zu dem Ziel ``/Users/foobar/MyDestination`` verschieben, wird das endgültige Ziel der Datei ``/Users/foobar/MyDestination/Users/foobar/SomeFolder/SubFolder`` sein. + +Auf jeden Fall behandelt dupeGuru Namenskonflikte indem es dem Ziel-Dateinamen eine Nummer voranstellt, wenn der Dateiname bereits im Zielverzeichnis existiert. + +**Eigener Befehl:** Diese Einstellung bestimmt den Befehl der durch "Führe eigenen Befehl aus" ausgeführt wird. Sie können jede externe Anwendung durch diese Aktion aufrufen. Dies ist zum Beispiel hilfreich, wenn Sie eine gute diff-Anwendung installiert haben. + +Das Format des Befehls ist das Selbe wie in einer Befehlszeile, außer das 2 Platzhalter vorhanden sind: **%d** und **%r**. Diese Platzhalter werden durch den Pfad des markierten Duplikates (%d) und dem Pfad der Duplikatereferenz ersetzt (%r). + +Wenn der Pfad Ihrer ausführbaren Datei Leerzeichen enthält, so schließen sie ihn bitte mit "" Zeichen ein. Sie sollten auch Platzhalter mit den Zitatzeichen einschließen, denn es ist möglich, das die Pfade der Duplikate und Referenzen ebenfalls Leerzeichen enthalten. Hier ist ein Beispiel eines eigenen Befehls:: + + "C:\Program Files\SuperDiffProg\SuperDiffProg.exe" "%d" "%r" diff --git a/help/de/_sources/quick_start.rst.txt b/help/de/_sources/quick_start.rst.txt new file mode 100644 index 00000000..412acbde --- /dev/null +++ b/help/de/_sources/quick_start.rst.txt @@ -0,0 +1,14 @@ +Schnellstart +============ + +Damit Sie sich schnell mit dupeGuru zurechtfinden, machen wir für den Anfang einen Standardscan mit den Voreinstellungen. + +* dupeGuru starten. +* Zu scannende Ordner entweder mit drag & drop oder dem "+" Knopf auswählen. +* Drücken Sie auf **Scan**. +* Warten Sie bis der Scanvorgang fertig ist. +* Betrachten Sie jedes Duplikat (die eingerückten Dateien) und überprüfen ob es wirklich ein Duplikat der Referenzdatei ist (die obere nicht eingerückte Datei ohne Markierungsfeld). +* Wenn eine Datei kein Duplikat ist, wählen Sie es aus und drücken auf **Aktionen-->Entferne Ausgewählte aus den Ergebnissen**. +* Erst wenn Sie sicher sind, das keine Falsch-Duplikate mehr in den Ergebnissen sind, drücken Sie auf **Bearbeiten-->Alle markieren**, und dann **Aktionen-->Verschiebe Markierte in den Mülleimer**. + +Das war nur ein einfacher Scan. Es gibt viele Optionen mit denen der Suchdurchlauf beeinflusst werden und einige Methoden zur Begutachtung und Veränderung der Ergebnisliste. Um mehr über sie zu erfahren, lesen Sie die restlichen Hilfedateien. diff --git a/help/de/_sources/reprioritize.rst.txt b/help/de/_sources/reprioritize.rst.txt new file mode 100644 index 00000000..ff37088b --- /dev/null +++ b/help/de/_sources/reprioritize.rst.txt @@ -0,0 +1,25 @@ +Re-Prioritizing duplicates +========================== + +dupeGuru tries to automatically determine which duplicate should go in each group's reference +position, but sometimes it gets it wrong. In many cases, clever dupe sorting with "Delta Values" +and "Dupes Only" options in addition to the "Make Selected into Reference" action does the trick, but +sometimes, a more powerful option is needed. This is where the Re-Prioritization dialog comes into +play. You can summon it through the "Re-Prioritize Results" item in the "Actions" menu. + +This dialog allows you to select criteria according to which a reference dupe will be selected in +each dupe group. The list of available criteria is on the left and the list of criteria you've +selected is on the right. + +A criteria is a category followed by an argument. For example, "Size (Highest)" means that the dupe +with the biggest size will win. "Folder (/foo/bar)" means that dupes in this folder will win. To add +a criterion to the rightmost list, first select a category in the combobox, then select a +subargument in the list below, and then click on the right pointing arrow button. + +The order of the list on the right is important (you can re-order items through drag & drop). When +picking a dupe for reference position, the first criterion is used. If there's a tie, the second +criterion is used and so on and so on. For example, if your arguments are "Size (Highest)" and then +"Filename (Doesn't end with a number)", the reference file that will be picked in a group will be +the biggest file, and if two or more files have the same size, the one that has a filename that +doesn't end with a number will be used. When all criteria result in ties, the order in which dupes +previously were in the group will be used. \ No newline at end of file diff --git a/help/de/_sources/results.rst.txt b/help/de/_sources/results.rst.txt new file mode 100644 index 00000000..ccd3f948 --- /dev/null +++ b/help/de/_sources/results.rst.txt @@ -0,0 +1,101 @@ +Ergebnisse +========== + +Sobald dupeGuru den Duplikatescan beendet hat, werden die Ergebnisse in Form einer Duplikate-Gruppenliste gezeigt. + +Über Duplikatgruppen +-------------------- + +Eine Duplikatgruppe ist eine Gruppe von übereinstimmenden Dateien. Jede Gruppe hat eine **Referenzdatei** und ein oder mehrere **Duplikate**. Die Referenzdatei ist die 1. Datei der Gruppe. Die Auswahlbox ist deaktiviert. Darunter befinden sich die eingerückten Duplikate. + +Sie können Duplikate markieren, aber niemals die Referenzdatei der Gruppe. Das ist eine Sicherheitsmaßnahme, die dupeGuru davon abhält nicht nur die Duplikate zu löschen, sondern auch die Referenzdatei. Sie wollen sicher nicht das das passiert, oder? + +Welche Dateien Referenz oder Duplikate sind hängt zuerst von ihrem Ordnerzustand ab. Eine Datei von einem Referenzordner ist immer Referenz einer Duplikatgruppe. Sind alle Dateien aus normalen Ordnern, bestimmt die Größe welche Datei die Referenz einer Gruppe sein wird. DupeGuru nimmt an, das Sie immer die größte Datei behalten wollen. Also übernimmt die größte Datei die Referenzposition. + +Sie können die Referenzdatei manuell verändern. Um das zu tun, wählen Sie das Duplikat aus, das zur Referenz befördert werden soll und drücken auf **Aktionen-->Mache Ausgewählte zur Referenz**. + +Ergebnisse beurteilen +--------------------- + +Obwohl Sie einfach auf **Markieren-->Alles markieren** gehen und dann **Aktionen-->Verschiebe Markierte in den Mülleimer** ausführen können, um schnell alle Duplikate zu löschen, ist es sinnvoll erst alle Duplikate zu betrachten, bevor man sie löscht. + +Um die Überprüfung zu erleichtern, können Sie das **Detail Panel** öffnen. Dieses Panel zeigt alle Details der gerade ausgewählten Datei sowie deren Referenz Details. Das ist sehr praktisch um schnell zu bestimmen, ob ein Duplikat wirklich ein Duplikat ist. Sie können außerdem auf die Datei doppelt klicken, um sie mit der verknüpften Anwendung zu öffnen. + +Wenn Sie mehr Falschpositive als echte Duplikate haben (die Filterempfindlichkeit sehr niedrig ist), ist es der beste Weg die echten Duplikate zu markieren und mit **Aktionen-->Verschiebe Markierte in den Mülleimer** zu entfernen. Haben Sie mehr echte Duplikate als Falschpositive, können Sie stattdessen alle unechten Duplikate markieren und **Entferne Markierte aus den Ergebnissen** nutzen. + +Markierung und Auswahl +---------------------- + +Ein **markiertes** Duplikat ist ein Duplikat, dessen kleine Box ein Häkchen hat. Ein **ausgewähltes** Duplikat ist hervorgehoben. Mehrfachauswahl wird in dupeGuru über den normalen Weg erreicht (Shift/Command/Steuerung Klick). Sie können die Markierung aller Duplikate umschalten, indem sie **Leertaste** drücken. + +.. todo:: Add "Non-numerical delta" information. + +Nur Duplikate anzeigen +---------------------- + +Wird dieser Modus aktiviert, so werden ausschließlich Duplikate ohne ihre respektive Referenzdatei gezeigt. Sie können diese Liste auswählen, markieren und sortieren, ganz wie im normalen Modus. + +Die dupeGuru Ergebnisse werden, im normalen Modus, nach der **Referenzdatei** der Duplikatgruppen sortiert. Das bedeutet zum Beispiel, um alle Duplikate mit der "exe" Erweiterung zu markieren, können Sie nicht einfach die Ergebnisse nach "Typ" ordnen um alle exe Duplikate zu erhalten, denn eine Gruppe kann aus mehreren Typen (Dateiarten) bestehen. Hier kommt der Nur-Duplikate Modus ins Spiel. Um alle "exe" Duplikate zu markieren, müssen Sie nur: + +* Nur Duplikate anzeigen aktivieren +* Die "Typ" Spalte über das "Spalten" Menü hinzufügen +* Auf "Typ" klicken, um die Liste zu sortieren +* Das erste Duplikat mit dem "exe" Typ lokalisieren. +* Es auswählen. +* Die Liste herunterscrollen und das letzte Duplikat mit dem "exe" Typ finden. +* Die Shift Taste halten und es auswählen. +* Leertaste drücken, um alle ausgewählten Duplikate zu markieren. + +Deltawerte +---------- + +Wenn Sie diesen Schalter aktivieren, zeigen einige Spalten den Wert relativ zur Duplikate-Referenz anstelle des absoluten Wertes an. Diese Deltawerte werden zusätzlich in einer anderen Farbe dargestellt, um sie leichter zu entdecken. Zum Beispiel, ein Duplikat ist 1,2 MB groß und die Referenz 1,4 MB, dann zeigt die Größe-Spalte -0,2 MB. + +Nur Duplikate anzeigen und Deltawerte +------------------------------------- + +Der Nur-Duplikate Modus enthüllt seine wahre Macht nur, wenn der Deltawerte Schalter aktiviert wurde. Wenn Sie ihn anschalten, werden relative Werte anstelle Absoluter gezeigt. Wenn Sie also, zum Beispiel, alle Duplikate die mehr als 300 KB von der Referenz verschieden sind aus der Ergebnisliste entfernen möchten, so sortieren Sie die Duplikate nach der Größe, wählen alle Duplikate mit weniger als -300 in der Größe-Spalte, löschen sie und tun das selbe für Duplikate mit mehr als +300 auf der Unterseite der Liste. + +Sie können dies außerdem nutzen, um die Referenzpriorität der Duplikateliste zu ändern. Wenn sie einen neuen Scan durchführen ist die größte Datei jeder Gruppe die Referenzdatei, solange keine Referenzordner existieren. Wollen Sie beispielsweise die Referenz nach der letztes Änderungszeit bestimmen, können Sie das Nur-Duplikate Ergebnis nach Änderungszeit in **absteigender** Reihenfolge sortieren, alle Duplikate mit einem Änderungszeit-Deltawert größergleich 0 auswählen und auf **Mache Ausgewählte zur Referenz** klicken. Der Grund warum die Sortierung absteigend erfolgen muss ist, wenn 2 Dateien der selben Duplikatgruppe ausgewählt werden und Sie **Mache Ausgewählte zur Referenz** klicken, dann wird nur der Erste der Liste wirklich als Referenz gesetzt. Da Sie nur die zuletzt geänderte Datei als Referenz haben möchten, stellt die vorangegangene Sortierung sicher, das der erste Eintrag der Liste auch der zuletzt Geänderte ist. + +Filtern +------- + +DupeGuru unterstützt das Filtern nach dem Scandurchlauf. Damit können Sie ihre Ergebnisse einschränken und diverse Aktionen auf einer Teilmenge ausführen. Beispielsweise ist es möglich alle Duplikate, deren Dateiname "copy" enthält mithilfe dieser Filterfunktion zu markieren. + +.. todo:: Qt has a toolbar search field now, not a menu item. + +**Windows/Linux:** Um diese Filterfunktion zu nutzen, klicken Sie Aktionen --> Filter anwenden, geben den Filter ein und drücken OK. Um zurück zu den ungefilterten Ergebnissen zu gelangen, gehen Sie auf Aktionen --> Filter entfernen. + +**Mac OS X:** Um diese Filterfunktion zu nutzen, geben Sie ihren Filter im "Filter" Suchfeld in der Symbolleiste ein. Um zurück zu den ungefilterten Ergebnissen zu gelangen, leeren Sie das Feld oder drücken auf "X". + +Im Einfach-Modus (Voreinstellung) wird jede Zeichenkette die Sie eingeben auch zum Filtern genutzt, mit Ausnahme einer Wildcard: **\***. Wenn Sie "[*]" als Filter nutzen, wird alles gefunden was die eckigen Klammern [] enthält, was auch immer zwischen diesen Klammern stehen mag. + +Für fortgeschrittenes Filtern, können Sie "Nutze reguläre Ausdrücke beim Filtern" aktivieren. Diese Funktion erlaubt es Ihnen **reguläre Ausdrücke** zu verwenden. Ein regulärer Ausdruck ist ein Filterkriterium für Text. Das zu erklären sprengt den Rahmen dieses Dokuments. Ein guter Platz für eine Einführung ist `regular-expressions.info `_. + +Filter ignorieren, im Einfach- und RegExp-Modus, die Groß- und Kleinschreibung. + +Damit der Filter etwas findet, muss Ihr regulärer Ausdruck nicht auf den gesamten Dateinamen passen. Der Name muss nur eine Zeichenkette enthalten die auf den Ausdruck zutrifft. + +Sie bemerken vielleicht, das nicht alle Duplikate in Ihren gefilterten Ergebnissen auf den Filter passen. Das liegt daran, sobald ein Duplikat einer Gruppe vom Filter gefunden wird, bleiben die restlichen Duplikate der Gruppe mit in der Liste, damit Sie einen besseren Überblick über den Kontext der Duplikate erhalten. Nicht passende Duplikate bleiben allerdings im "Referenz-Modus". Dadurch können Sie sicher sein Aktionen wie "Alles Markieren" anzuwenden und nur gefilterte Duplikate zu markieren. + +Aktionen Menü +------------- + +* **Ignorier-Liste leeren:** Entfernt alle ignorierten Treffer die Sie hinzugefügt haben. Um wirksam zu sein, muss ein neuer Scan für die gerade gelöschte Ignorier-Liste gestartet werden. +* **Exportiere als XHTML:** Nimmt die aktuellen Ergebnisse und erstellt aus ihnen eine XHTML Datei. Die Spalten die sichtbar werden, wenn sie auf diesen Knopf drücken, werden die Spalten in der XHTML Datei sein. Die Datei wird automatisch mit dem Standardbrowser geöffnet. +* **Verschiebe Markierte in den Mülleimer:** Verschiebt alle markierten Duplikate in den Mülleimer. +* **Lösche Markierte und ersetze mit Hardlinks:** Verschiebt alle Markierten in den Mülleimer. Danach werden die gelöschten Dateien jedoch mit Hardlinks zur Referenzdatei ersetzt `hard link `_ . (Nur OS X und Linux) +* **Verschiebe Markierte nach...:** Fragt nach einem Ziel und verschiebt alle Markierten zum Ziel. Der Quelldateipfad wird vielleicht am Ziel neu erstellt, abhängig von der "Kopieren und Verschieben" Einstellung. +* **Kopiere Markierte nach...:** Fragt nach einem Ziel und kopiert alle Markierten zum Ziel. Der Quelldateipfad wird vielleicht am Ziel neu erstellt, abhängig von der "Kopieren und Verschieben" Einstellung. +* **Entferne Markierte aus den Ergebnissen:** Entfernt alle markierte Duplikate aus den Ergebnissen. Die wirklichen Dateien werden nicht angerührt und bleiben wo sie sind. +* **Entferne Ausgewählte aus den Ergebnissen:** Entfernt alle ausgewählten Duplikate aus den Ergebnissen. Beachten Sie das ausgewählte Referenzen ignoriert werden, nur Duplikate können entfernt werden. +* **Mache Ausgewählte zur Referenz:** Ernenne alle ausgewählten Duplikate zur Referenz. Ist ein Duplikat Teil einer Gruppe, die eine Referenzdatei aus einem Referenzordner hat (blaue Farbe), wird keine Aktion für dieses Duplikat durchgeführt. Ist mehr als ein Duplikat aus der selben Gruppe ausgewählt, wird nur das Erste jeder Gruppe befördert. +* **Füge Ausgewählte der Ignorier-Liste hinzu:** Dies entfernt zuerst alle ausgewählten Duplikate aus den Ergebnissen und fügt danach das aktuelle Duplikat und die Referenz der Ignorier-Liste hinzu. Diese Treffer werden bei zukünftigen Scans nicht mehr angezeigt. Das Duplikat selbst kann wieder auftauchen, es wird dann jedoch zur einer anderen Referenz gehören. Die Ignorier-Liste kann mit dem Ignorier-Liste leeren Kommando gelöscht werden. +* **Öffne Ausgewählte mit Standardanwendung:** Öffnet die Datei mit der Anwendung die mit dem Dateityp verknüpft ist. +* **Zeige Ausgewählte:** Öffnet den Ordner der die ausgewählte Datei enthält. +* **Eigenen Befehl ausführen:** Ruft die in den Einstellungen definierte externe Anwendung auf und nutzt die aktuelle Auswahl als Argumente für den Aufruf. +* **Ausgewählte umbenennen:** Fragt nach einem neuen Namen und benennt die ausgewählte Datei um. + +.. todo:: Add Move and iPhoto/iTunes warning +.. todo:: Add "Deletion Options" section. \ No newline at end of file diff --git a/help/de/_static/_stemmer.js b/help/de/_static/_stemmer.js new file mode 100644 index 00000000..4f1dc1cf --- /dev/null +++ b/help/de/_static/_stemmer.js @@ -0,0 +1,2506 @@ +// generatedy by JSX compiler 0.9.89 (2014-05-20 06:01:03 +0900; 8e8c6105f36f3dfe440ea026a3c93a3444977102) +var JSX = {}; +(function (JSX) { +/** + * extends the class + */ +function $__jsx_extend(derivations, base) { + var ctor = function () {}; + ctor.prototype = base.prototype; + var proto = new ctor(); + for (var i in derivations) { + derivations[i].prototype = proto; + } +} + +/** + * copies the implementations from source interface to target + */ +function $__jsx_merge_interface(target, source) { + for (var k in source.prototype) + if (source.prototype.hasOwnProperty(k)) + target.prototype[k] = source.prototype[k]; +} + +/** + * defers the initialization of the property + */ +function $__jsx_lazy_init(obj, prop, func) { + function reset(obj, prop, value) { + delete obj[prop]; + obj[prop] = value; + return value; + } + + Object.defineProperty(obj, prop, { + get: function () { + return reset(obj, prop, func()); + }, + set: function (v) { + reset(obj, prop, v); + }, + enumerable: true, + configurable: true + }); +} + +var $__jsx_imul = Math.imul; +if (typeof $__jsx_imul === "undefined") { + $__jsx_imul = function (a, b) { + var ah = (a >>> 16) & 0xffff; + var al = a & 0xffff; + var bh = (b >>> 16) & 0xffff; + var bl = b & 0xffff; + return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0); + }; +} + +/** + * fused int-ops with side-effects + */ +function $__jsx_ipadd(o, p, r) { + return o[p] = (o[p] + r) | 0; +} +function $__jsx_ipsub(o, p, r) { + return o[p] = (o[p] - r) | 0; +} +function $__jsx_ipmul(o, p, r) { + return o[p] = $__jsx_imul(o[p], r); +} +function $__jsx_ipdiv(o, p, r) { + return o[p] = (o[p] / r) | 0; +} +function $__jsx_ipmod(o, p, r) { + return o[p] = (o[p] % r) | 0; +} +function $__jsx_ippostinc(o, p) { + var v = o[p]; + o[p] = (v + 1) | 0; + return v; +} +function $__jsx_ippostdec(o, p) { + var v = o[p]; + o[p] = (v - 1) | 0; + return v; +} + +/** + * non-inlined version of Array#each + */ +function $__jsx_forEach(o, f) { + var l = o.length; + for (var i = 0; i < l; ++i) + f(o[i]); +} + +/* + * global functions, renamed to avoid conflict with local variable names + */ +var $__jsx_parseInt = parseInt; +var $__jsx_parseFloat = parseFloat; +function $__jsx_isNaN(n) { return n !== n; } +var $__jsx_isFinite = isFinite; + +var $__jsx_encodeURIComponent = encodeURIComponent; +var $__jsx_decodeURIComponent = decodeURIComponent; +var $__jsx_encodeURI = encodeURI; +var $__jsx_decodeURI = decodeURI; + +var $__jsx_ObjectToString = Object.prototype.toString; +var $__jsx_ObjectHasOwnProperty = Object.prototype.hasOwnProperty; + +/* + * profiler object, initialized afterwards + */ +function $__jsx_profiler() { +} + +/* + * public interface to JSX code + */ +JSX.require = function (path) { + var m = $__jsx_classMap[path]; + return m !== undefined ? m : null; +}; + +JSX.profilerIsRunning = function () { + return $__jsx_profiler.getResults != null; +}; + +JSX.getProfileResults = function () { + return ($__jsx_profiler.getResults || function () { return {}; })(); +}; + +JSX.postProfileResults = function (url, cb) { + if ($__jsx_profiler.postResults == null) + throw new Error("profiler has not been turned on"); + return $__jsx_profiler.postResults(url, cb); +}; + +JSX.resetProfileResults = function () { + if ($__jsx_profiler.resetResults == null) + throw new Error("profiler has not been turned on"); + return $__jsx_profiler.resetResults(); +}; +JSX.DEBUG = false; +var GeneratorFunction$0 = +(function () { + try { + return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); + } catch (e) { + return function GeneratorFunction () {}; + } +})(); +var __jsx_generator_object$0 = +(function () { + function __jsx_generator_object() { + this.__next = 0; + this.__loop = null; + this.__seed = null; + this.__value = undefined; + this.__status = 0; // SUSPENDED: 0, ACTIVE: 1, DEAD: 2 + } + + __jsx_generator_object.prototype.next = function (seed) { + switch (this.__status) { + case 0: + this.__status = 1; + this.__seed = seed; + + // go next! + this.__loop(this.__next); + + var done = false; + if (this.__next != -1) { + this.__status = 0; + } else { + this.__status = 2; + done = true; + } + return { value: this.__value, done: done }; + case 1: + throw new Error("Generator is already running"); + case 2: + throw new Error("Generator is already finished"); + default: + throw new Error("Unexpected generator internal state"); + } + }; + + return __jsx_generator_object; +}()); +function Among(s, substring_i, result) { + this.s_size = s.length; + this.s = s; + this.substring_i = substring_i; + this.result = result; + this.method = null; + this.instance = null; +}; + +function Among$0(s, substring_i, result, method, instance) { + this.s_size = s.length; + this.s = s; + this.substring_i = substring_i; + this.result = result; + this.method = method; + this.instance = instance; +}; + +$__jsx_extend([Among, Among$0], Object); +function Stemmer() { +}; + +$__jsx_extend([Stemmer], Object); +function BaseStemmer() { + var current$0; + var cursor$0; + var limit$0; + this.cache = ({ }); + current$0 = this.current = ""; + cursor$0 = this.cursor = 0; + limit$0 = this.limit = current$0.length; + this.limit_backward = 0; + this.bra = cursor$0; + this.ket = limit$0; +}; + +$__jsx_extend([BaseStemmer], Stemmer); +BaseStemmer.prototype.setCurrent$S = function (value) { + var current$0; + var cursor$0; + var limit$0; + current$0 = this.current = value; + cursor$0 = this.cursor = 0; + limit$0 = this.limit = current$0.length; + this.limit_backward = 0; + this.bra = cursor$0; + this.ket = limit$0; +}; + + +function BaseStemmer$setCurrent$LBaseStemmer$S($this, value) { + var current$0; + var cursor$0; + var limit$0; + current$0 = $this.current = value; + cursor$0 = $this.cursor = 0; + limit$0 = $this.limit = current$0.length; + $this.limit_backward = 0; + $this.bra = cursor$0; + $this.ket = limit$0; +}; + +BaseStemmer.setCurrent$LBaseStemmer$S = BaseStemmer$setCurrent$LBaseStemmer$S; + +BaseStemmer.prototype.getCurrent$ = function () { + return this.current; +}; + + +function BaseStemmer$getCurrent$LBaseStemmer$($this) { + return $this.current; +}; + +BaseStemmer.getCurrent$LBaseStemmer$ = BaseStemmer$getCurrent$LBaseStemmer$; + +BaseStemmer.prototype.copy_from$LBaseStemmer$ = function (other) { + this.current = other.current; + this.cursor = other.cursor; + this.limit = other.limit; + this.limit_backward = other.limit_backward; + this.bra = other.bra; + this.ket = other.ket; +}; + + +function BaseStemmer$copy_from$LBaseStemmer$LBaseStemmer$($this, other) { + $this.current = other.current; + $this.cursor = other.cursor; + $this.limit = other.limit; + $this.limit_backward = other.limit_backward; + $this.bra = other.bra; + $this.ket = other.ket; +}; + +BaseStemmer.copy_from$LBaseStemmer$LBaseStemmer$ = BaseStemmer$copy_from$LBaseStemmer$LBaseStemmer$; + +BaseStemmer.prototype.in_grouping$AIII = function (s, min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor >= this.limit) { + return false; + } + ch = this.current.charCodeAt(this.cursor); + if (ch > max || ch < min) { + return false; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$in_grouping$LBaseStemmer$AIII($this, s, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor >= $this.limit) { + return false; + } + ch = $this.current.charCodeAt($this.cursor); + if (ch > max || ch < min) { + return false; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.in_grouping$LBaseStemmer$AIII = BaseStemmer$in_grouping$LBaseStemmer$AIII; + +BaseStemmer.prototype.in_grouping_b$AIII = function (s, min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor <= this.limit_backward) { + return false; + } + ch = this.current.charCodeAt(this.cursor - 1); + if (ch > max || ch < min) { + return false; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$in_grouping_b$LBaseStemmer$AIII($this, s, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor <= $this.limit_backward) { + return false; + } + ch = $this.current.charCodeAt($this.cursor - 1); + if (ch > max || ch < min) { + return false; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.in_grouping_b$LBaseStemmer$AIII = BaseStemmer$in_grouping_b$LBaseStemmer$AIII; + +BaseStemmer.prototype.out_grouping$AIII = function (s, min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor >= this.limit) { + return false; + } + ch = this.current.charCodeAt(this.cursor); + if (ch > max || ch < min) { + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; + } + ch -= min; + if ((s[ch >>> 3] & 0X1 << (ch & 0x7)) === 0) { + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; + } + return false; +}; + + +function BaseStemmer$out_grouping$LBaseStemmer$AIII($this, s, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor >= $this.limit) { + return false; + } + ch = $this.current.charCodeAt($this.cursor); + if (ch > max || ch < min) { + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; + } + ch -= min; + if ((s[ch >>> 3] & 0X1 << (ch & 0x7)) === 0) { + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; + } + return false; +}; + +BaseStemmer.out_grouping$LBaseStemmer$AIII = BaseStemmer$out_grouping$LBaseStemmer$AIII; + +BaseStemmer.prototype.out_grouping_b$AIII = function (s, min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor <= this.limit_backward) { + return false; + } + ch = this.current.charCodeAt(this.cursor - 1); + if (ch > max || ch < min) { + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; + } + return false; +}; + + +function BaseStemmer$out_grouping_b$LBaseStemmer$AIII($this, s, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor <= $this.limit_backward) { + return false; + } + ch = $this.current.charCodeAt($this.cursor - 1); + if (ch > max || ch < min) { + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; + } + return false; +}; + +BaseStemmer.out_grouping_b$LBaseStemmer$AIII = BaseStemmer$out_grouping_b$LBaseStemmer$AIII; + +BaseStemmer.prototype.in_range$II = function (min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor >= this.limit) { + return false; + } + ch = this.current.charCodeAt(this.cursor); + if (ch > max || ch < min) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$in_range$LBaseStemmer$II($this, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor >= $this.limit) { + return false; + } + ch = $this.current.charCodeAt($this.cursor); + if (ch > max || ch < min) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.in_range$LBaseStemmer$II = BaseStemmer$in_range$LBaseStemmer$II; + +BaseStemmer.prototype.in_range_b$II = function (min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor <= this.limit_backward) { + return false; + } + ch = this.current.charCodeAt(this.cursor - 1); + if (ch > max || ch < min) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$in_range_b$LBaseStemmer$II($this, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor <= $this.limit_backward) { + return false; + } + ch = $this.current.charCodeAt($this.cursor - 1); + if (ch > max || ch < min) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.in_range_b$LBaseStemmer$II = BaseStemmer$in_range_b$LBaseStemmer$II; + +BaseStemmer.prototype.out_range$II = function (min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor >= this.limit) { + return false; + } + ch = this.current.charCodeAt(this.cursor); + if (! (ch > max || ch < min)) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$out_range$LBaseStemmer$II($this, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor >= $this.limit) { + return false; + } + ch = $this.current.charCodeAt($this.cursor); + if (! (ch > max || ch < min)) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.out_range$LBaseStemmer$II = BaseStemmer$out_range$LBaseStemmer$II; + +BaseStemmer.prototype.out_range_b$II = function (min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor <= this.limit_backward) { + return false; + } + ch = this.current.charCodeAt(this.cursor - 1); + if (! (ch > max || ch < min)) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$out_range_b$LBaseStemmer$II($this, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor <= $this.limit_backward) { + return false; + } + ch = $this.current.charCodeAt($this.cursor - 1); + if (! (ch > max || ch < min)) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.out_range_b$LBaseStemmer$II = BaseStemmer$out_range_b$LBaseStemmer$II; + +BaseStemmer.prototype.eq_s$IS = function (s_size, s) { + var cursor$0; + if (((this.limit - this.cursor) | 0) < s_size) { + return false; + } + if (this.current.slice(cursor$0 = this.cursor, ((cursor$0 + s_size) | 0)) !== s) { + return false; + } + this.cursor = (this.cursor + s_size) | 0; + return true; +}; + + +function BaseStemmer$eq_s$LBaseStemmer$IS($this, s_size, s) { + var cursor$0; + if ((($this.limit - $this.cursor) | 0) < s_size) { + return false; + } + if ($this.current.slice(cursor$0 = $this.cursor, ((cursor$0 + s_size) | 0)) !== s) { + return false; + } + $this.cursor = ($this.cursor + s_size) | 0; + return true; +}; + +BaseStemmer.eq_s$LBaseStemmer$IS = BaseStemmer$eq_s$LBaseStemmer$IS; + +BaseStemmer.prototype.eq_s_b$IS = function (s_size, s) { + var cursor$0; + if (((this.cursor - this.limit_backward) | 0) < s_size) { + return false; + } + if (this.current.slice((((cursor$0 = this.cursor) - s_size) | 0), cursor$0) !== s) { + return false; + } + this.cursor = (this.cursor - s_size) | 0; + return true; +}; + + +function BaseStemmer$eq_s_b$LBaseStemmer$IS($this, s_size, s) { + var cursor$0; + if ((($this.cursor - $this.limit_backward) | 0) < s_size) { + return false; + } + if ($this.current.slice((((cursor$0 = $this.cursor) - s_size) | 0), cursor$0) !== s) { + return false; + } + $this.cursor = ($this.cursor - s_size) | 0; + return true; +}; + +BaseStemmer.eq_s_b$LBaseStemmer$IS = BaseStemmer$eq_s_b$LBaseStemmer$IS; + +BaseStemmer.prototype.eq_v$S = function (s) { + return BaseStemmer$eq_s$LBaseStemmer$IS(this, s.length, s); +}; + + +function BaseStemmer$eq_v$LBaseStemmer$S($this, s) { + return BaseStemmer$eq_s$LBaseStemmer$IS($this, s.length, s); +}; + +BaseStemmer.eq_v$LBaseStemmer$S = BaseStemmer$eq_v$LBaseStemmer$S; + +BaseStemmer.prototype.eq_v_b$S = function (s) { + return BaseStemmer$eq_s_b$LBaseStemmer$IS(this, s.length, s); +}; + + +function BaseStemmer$eq_v_b$LBaseStemmer$S($this, s) { + return BaseStemmer$eq_s_b$LBaseStemmer$IS($this, s.length, s); +}; + +BaseStemmer.eq_v_b$LBaseStemmer$S = BaseStemmer$eq_v_b$LBaseStemmer$S; + +BaseStemmer.prototype.find_among$ALAmong$I = function (v, v_size) { + var i; + var j; + var c; + var l; + var common_i; + var common_j; + var first_key_inspected; + var k; + var diff; + var common; + var w; + var i2; + var res; + i = 0; + j = v_size; + c = this.cursor; + l = this.limit; + common_i = 0; + common_j = 0; + first_key_inspected = false; + while (true) { + k = i + (j - i >>> 1); + diff = 0; + common = (common_i < common_j ? common_i : common_j); + w = v[k]; + for (i2 = common; i2 < w.s_size; i2++) { + if (c + common === l) { + diff = -1; + break; + } + diff = this.current.charCodeAt(c + common) - w.s.charCodeAt(i2); + if (diff !== 0) { + break; + } + common++; + } + if (diff < 0) { + j = k; + common_j = common; + } else { + i = k; + common_i = common; + } + if (j - i <= 1) { + if (i > 0) { + break; + } + if (j === i) { + break; + } + if (first_key_inspected) { + break; + } + first_key_inspected = true; + } + } + while (true) { + w = v[i]; + if (common_i >= w.s_size) { + this.cursor = (c + w.s_size | 0); + if (w.method == null) { + return w.result; + } + res = w.method(w.instance); + this.cursor = (c + w.s_size | 0); + if (res) { + return w.result; + } + } + i = w.substring_i; + if (i < 0) { + return 0; + } + } + return -1; +}; + + +function BaseStemmer$find_among$LBaseStemmer$ALAmong$I($this, v, v_size) { + var i; + var j; + var c; + var l; + var common_i; + var common_j; + var first_key_inspected; + var k; + var diff; + var common; + var w; + var i2; + var res; + i = 0; + j = v_size; + c = $this.cursor; + l = $this.limit; + common_i = 0; + common_j = 0; + first_key_inspected = false; + while (true) { + k = i + (j - i >>> 1); + diff = 0; + common = (common_i < common_j ? common_i : common_j); + w = v[k]; + for (i2 = common; i2 < w.s_size; i2++) { + if (c + common === l) { + diff = -1; + break; + } + diff = $this.current.charCodeAt(c + common) - w.s.charCodeAt(i2); + if (diff !== 0) { + break; + } + common++; + } + if (diff < 0) { + j = k; + common_j = common; + } else { + i = k; + common_i = common; + } + if (j - i <= 1) { + if (i > 0) { + break; + } + if (j === i) { + break; + } + if (first_key_inspected) { + break; + } + first_key_inspected = true; + } + } + while (true) { + w = v[i]; + if (common_i >= w.s_size) { + $this.cursor = (c + w.s_size | 0); + if (w.method == null) { + return w.result; + } + res = w.method(w.instance); + $this.cursor = (c + w.s_size | 0); + if (res) { + return w.result; + } + } + i = w.substring_i; + if (i < 0) { + return 0; + } + } + return -1; +}; + +BaseStemmer.find_among$LBaseStemmer$ALAmong$I = BaseStemmer$find_among$LBaseStemmer$ALAmong$I; + +BaseStemmer.prototype.find_among_b$ALAmong$I = function (v, v_size) { + var i; + var j; + var c; + var lb; + var common_i; + var common_j; + var first_key_inspected; + var k; + var diff; + var common; + var w; + var i2; + var res; + i = 0; + j = v_size; + c = this.cursor; + lb = this.limit_backward; + common_i = 0; + common_j = 0; + first_key_inspected = false; + while (true) { + k = i + (j - i >> 1); + diff = 0; + common = (common_i < common_j ? common_i : common_j); + w = v[k]; + for (i2 = w.s_size - 1 - common; i2 >= 0; i2--) { + if (c - common === lb) { + diff = -1; + break; + } + diff = this.current.charCodeAt(c - 1 - common) - w.s.charCodeAt(i2); + if (diff !== 0) { + break; + } + common++; + } + if (diff < 0) { + j = k; + common_j = common; + } else { + i = k; + common_i = common; + } + if (j - i <= 1) { + if (i > 0) { + break; + } + if (j === i) { + break; + } + if (first_key_inspected) { + break; + } + first_key_inspected = true; + } + } + while (true) { + w = v[i]; + if (common_i >= w.s_size) { + this.cursor = (c - w.s_size | 0); + if (w.method == null) { + return w.result; + } + res = w.method(this); + this.cursor = (c - w.s_size | 0); + if (res) { + return w.result; + } + } + i = w.substring_i; + if (i < 0) { + return 0; + } + } + return -1; +}; + + +function BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, v, v_size) { + var i; + var j; + var c; + var lb; + var common_i; + var common_j; + var first_key_inspected; + var k; + var diff; + var common; + var w; + var i2; + var res; + i = 0; + j = v_size; + c = $this.cursor; + lb = $this.limit_backward; + common_i = 0; + common_j = 0; + first_key_inspected = false; + while (true) { + k = i + (j - i >> 1); + diff = 0; + common = (common_i < common_j ? common_i : common_j); + w = v[k]; + for (i2 = w.s_size - 1 - common; i2 >= 0; i2--) { + if (c - common === lb) { + diff = -1; + break; + } + diff = $this.current.charCodeAt(c - 1 - common) - w.s.charCodeAt(i2); + if (diff !== 0) { + break; + } + common++; + } + if (diff < 0) { + j = k; + common_j = common; + } else { + i = k; + common_i = common; + } + if (j - i <= 1) { + if (i > 0) { + break; + } + if (j === i) { + break; + } + if (first_key_inspected) { + break; + } + first_key_inspected = true; + } + } + while (true) { + w = v[i]; + if (common_i >= w.s_size) { + $this.cursor = (c - w.s_size | 0); + if (w.method == null) { + return w.result; + } + res = w.method($this); + $this.cursor = (c - w.s_size | 0); + if (res) { + return w.result; + } + } + i = w.substring_i; + if (i < 0) { + return 0; + } + } + return -1; +}; + +BaseStemmer.find_among_b$LBaseStemmer$ALAmong$I = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I; + +BaseStemmer.prototype.replace_s$IIS = function (c_bra, c_ket, s) { + var adjustment; + adjustment = ((s.length - (((c_ket - c_bra) | 0))) | 0); + this.current = this.current.slice(0, c_bra) + s + this.current.slice(c_ket); + this.limit = (this.limit + adjustment) | 0; + if (this.cursor >= c_ket) { + this.cursor = (this.cursor + adjustment) | 0; + } else if (this.cursor > c_bra) { + this.cursor = c_bra; + } + return (adjustment | 0); +}; + + +function BaseStemmer$replace_s$LBaseStemmer$IIS($this, c_bra, c_ket, s) { + var adjustment; + adjustment = ((s.length - (((c_ket - c_bra) | 0))) | 0); + $this.current = $this.current.slice(0, c_bra) + s + $this.current.slice(c_ket); + $this.limit = ($this.limit + adjustment) | 0; + if ($this.cursor >= c_ket) { + $this.cursor = ($this.cursor + adjustment) | 0; + } else if ($this.cursor > c_bra) { + $this.cursor = c_bra; + } + return (adjustment | 0); +}; + +BaseStemmer.replace_s$LBaseStemmer$IIS = BaseStemmer$replace_s$LBaseStemmer$IIS; + +BaseStemmer.prototype.slice_check$ = function () { + var bra$0; + var ket$0; + var limit$0; + return ((bra$0 = this.bra) < 0 || bra$0 > (ket$0 = this.ket) || ket$0 > (limit$0 = this.limit) || limit$0 > this.current.length ? false : true); +}; + + +function BaseStemmer$slice_check$LBaseStemmer$($this) { + var bra$0; + var ket$0; + var limit$0; + return ((bra$0 = $this.bra) < 0 || bra$0 > (ket$0 = $this.ket) || ket$0 > (limit$0 = $this.limit) || limit$0 > $this.current.length ? false : true); +}; + +BaseStemmer.slice_check$LBaseStemmer$ = BaseStemmer$slice_check$LBaseStemmer$; + +BaseStemmer.prototype.slice_from$S = function (s) { + var result; + var bra$0; + var ket$0; + var limit$0; + result = false; + if ((bra$0 = this.bra) < 0 || bra$0 > (ket$0 = this.ket) || ket$0 > (limit$0 = this.limit) || limit$0 > this.current.length ? false : true) { + BaseStemmer$replace_s$LBaseStemmer$IIS(this, this.bra, this.ket, s); + result = true; + } + return result; +}; + + +function BaseStemmer$slice_from$LBaseStemmer$S($this, s) { + var result; + var bra$0; + var ket$0; + var limit$0; + result = false; + if ((bra$0 = $this.bra) < 0 || bra$0 > (ket$0 = $this.ket) || ket$0 > (limit$0 = $this.limit) || limit$0 > $this.current.length ? false : true) { + BaseStemmer$replace_s$LBaseStemmer$IIS($this, $this.bra, $this.ket, s); + result = true; + } + return result; +}; + +BaseStemmer.slice_from$LBaseStemmer$S = BaseStemmer$slice_from$LBaseStemmer$S; + +BaseStemmer.prototype.slice_del$ = function () { + return BaseStemmer$slice_from$LBaseStemmer$S(this, ""); +}; + + +function BaseStemmer$slice_del$LBaseStemmer$($this) { + return BaseStemmer$slice_from$LBaseStemmer$S($this, ""); +}; + +BaseStemmer.slice_del$LBaseStemmer$ = BaseStemmer$slice_del$LBaseStemmer$; + +BaseStemmer.prototype.insert$IIS = function (c_bra, c_ket, s) { + var adjustment; + adjustment = BaseStemmer$replace_s$LBaseStemmer$IIS(this, c_bra, c_ket, s); + if (c_bra <= this.bra) { + this.bra = (this.bra + adjustment) | 0; + } + if (c_bra <= this.ket) { + this.ket = (this.ket + adjustment) | 0; + } +}; + + +function BaseStemmer$insert$LBaseStemmer$IIS($this, c_bra, c_ket, s) { + var adjustment; + adjustment = BaseStemmer$replace_s$LBaseStemmer$IIS($this, c_bra, c_ket, s); + if (c_bra <= $this.bra) { + $this.bra = ($this.bra + adjustment) | 0; + } + if (c_bra <= $this.ket) { + $this.ket = ($this.ket + adjustment) | 0; + } +}; + +BaseStemmer.insert$LBaseStemmer$IIS = BaseStemmer$insert$LBaseStemmer$IIS; + +BaseStemmer.prototype.slice_to$S = function (s) { + var result; + var bra$0; + var ket$0; + var limit$0; + result = ''; + if ((bra$0 = this.bra) < 0 || bra$0 > (ket$0 = this.ket) || ket$0 > (limit$0 = this.limit) || limit$0 > this.current.length ? false : true) { + result = this.current.slice(this.bra, this.ket); + } + return result; +}; + + +function BaseStemmer$slice_to$LBaseStemmer$S($this, s) { + var result; + var bra$0; + var ket$0; + var limit$0; + result = ''; + if ((bra$0 = $this.bra) < 0 || bra$0 > (ket$0 = $this.ket) || ket$0 > (limit$0 = $this.limit) || limit$0 > $this.current.length ? false : true) { + result = $this.current.slice($this.bra, $this.ket); + } + return result; +}; + +BaseStemmer.slice_to$LBaseStemmer$S = BaseStemmer$slice_to$LBaseStemmer$S; + +BaseStemmer.prototype.assign_to$S = function (s) { + return this.current.slice(0, this.limit); +}; + + +function BaseStemmer$assign_to$LBaseStemmer$S($this, s) { + return $this.current.slice(0, $this.limit); +}; + +BaseStemmer.assign_to$LBaseStemmer$S = BaseStemmer$assign_to$LBaseStemmer$S; + +BaseStemmer.prototype.stem$ = function () { + return false; +}; + + +BaseStemmer.prototype.stemWord$S = function (word) { + var result; + var current$0; + var cursor$0; + var limit$0; + result = this.cache['.' + word]; + if (result == null) { + current$0 = this.current = word; + cursor$0 = this.cursor = 0; + limit$0 = this.limit = current$0.length; + this.limit_backward = 0; + this.bra = cursor$0; + this.ket = limit$0; + this.stem$(); + result = this.current; + this.cache['.' + word] = result; + } + return result; +}; + +BaseStemmer.prototype.stemWord = BaseStemmer.prototype.stemWord$S; + +BaseStemmer.prototype.stemWords$AS = function (words) { + var results; + var i; + var word; + var result; + var current$0; + var cursor$0; + var limit$0; + results = [ ]; + for (i = 0; i < words.length; i++) { + word = words[i]; + result = this.cache['.' + word]; + if (result == null) { + current$0 = this.current = word; + cursor$0 = this.cursor = 0; + limit$0 = this.limit = current$0.length; + this.limit_backward = 0; + this.bra = cursor$0; + this.ket = limit$0; + this.stem$(); + result = this.current; + this.cache['.' + word] = result; + } + results.push(result); + } + return results; +}; + +BaseStemmer.prototype.stemWords = BaseStemmer.prototype.stemWords$AS; + +function GermanStemmer() { + BaseStemmer.call(this); + this.I_x = 0; + this.I_p2 = 0; + this.I_p1 = 0; +}; + +$__jsx_extend([GermanStemmer], BaseStemmer); +GermanStemmer.prototype.copy_from$LGermanStemmer$ = function (other) { + this.I_x = other.I_x; + this.I_p2 = other.I_p2; + this.I_p1 = other.I_p1; + BaseStemmer$copy_from$LBaseStemmer$LBaseStemmer$(this, other); +}; + +GermanStemmer.prototype.copy_from = GermanStemmer.prototype.copy_from$LGermanStemmer$; + +GermanStemmer.prototype.r_prelude$ = function () { + var v_1; + var v_2; + var v_3; + var v_4; + var v_5; + var v_6; + var lab1; + var lab2; + var lab3; + var lab5; + var lab7; + var lab8; + var lab9; + var cursor$0; + var cursor$1; + var $__jsx_postinc_t; + v_1 = this.cursor; +replab0: + while (true) { + v_2 = this.cursor; + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + lab2 = true; + lab2: + while (lab2 === true) { + lab2 = false; + v_3 = this.cursor; + lab3 = true; + lab3: + while (lab3 === true) { + lab3 = false; + this.bra = this.cursor; + if (! BaseStemmer$eq_s$LBaseStemmer$IS(this, 1, "\u00DF")) { + break lab3; + } + this.ket = this.cursor; + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "ss")) { + return false; + } + break lab2; + } + cursor$0 = this.cursor = v_3; + if (cursor$0 >= this.limit) { + break lab1; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + continue replab0; + } + this.cursor = v_2; + break replab0; + } + this.cursor = v_1; +replab4: + while (true) { + v_4 = this.cursor; + lab5 = true; + lab5: + while (lab5 === true) { + lab5 = false; + golab6: + while (true) { + v_5 = this.cursor; + lab7 = true; + lab7: + while (lab7 === true) { + lab7 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, GermanStemmer.g_v, 97, 252)) { + break lab7; + } + this.bra = this.cursor; + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + v_6 = this.cursor; + lab9 = true; + lab9: + while (lab9 === true) { + lab9 = false; + if (! BaseStemmer$eq_s$LBaseStemmer$IS(this, 1, "u")) { + break lab9; + } + this.ket = this.cursor; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, GermanStemmer.g_v, 97, 252)) { + break lab9; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "U")) { + return false; + } + break lab8; + } + this.cursor = v_6; + if (! BaseStemmer$eq_s$LBaseStemmer$IS(this, 1, "y")) { + break lab7; + } + this.ket = this.cursor; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, GermanStemmer.g_v, 97, 252)) { + break lab7; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "Y")) { + return false; + } + } + this.cursor = v_5; + break golab6; + } + cursor$1 = this.cursor = v_5; + if (cursor$1 >= this.limit) { + break lab5; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + continue replab4; + } + this.cursor = v_4; + break replab4; + } + return true; +}; + +GermanStemmer.prototype.r_prelude = GermanStemmer.prototype.r_prelude$; + +function GermanStemmer$r_prelude$LGermanStemmer$($this) { + var v_1; + var v_2; + var v_3; + var v_4; + var v_5; + var v_6; + var lab1; + var lab2; + var lab3; + var lab5; + var lab7; + var lab8; + var lab9; + var cursor$0; + var cursor$1; + var $__jsx_postinc_t; + v_1 = $this.cursor; +replab0: + while (true) { + v_2 = $this.cursor; + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + lab2 = true; + lab2: + while (lab2 === true) { + lab2 = false; + v_3 = $this.cursor; + lab3 = true; + lab3: + while (lab3 === true) { + lab3 = false; + $this.bra = $this.cursor; + if (! BaseStemmer$eq_s$LBaseStemmer$IS($this, 1, "\u00DF")) { + break lab3; + } + $this.ket = $this.cursor; + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "ss")) { + return false; + } + break lab2; + } + cursor$0 = $this.cursor = v_3; + if (cursor$0 >= $this.limit) { + break lab1; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + continue replab0; + } + $this.cursor = v_2; + break replab0; + } + $this.cursor = v_1; +replab4: + while (true) { + v_4 = $this.cursor; + lab5 = true; + lab5: + while (lab5 === true) { + lab5 = false; + golab6: + while (true) { + v_5 = $this.cursor; + lab7 = true; + lab7: + while (lab7 === true) { + lab7 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, GermanStemmer.g_v, 97, 252)) { + break lab7; + } + $this.bra = $this.cursor; + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + v_6 = $this.cursor; + lab9 = true; + lab9: + while (lab9 === true) { + lab9 = false; + if (! BaseStemmer$eq_s$LBaseStemmer$IS($this, 1, "u")) { + break lab9; + } + $this.ket = $this.cursor; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, GermanStemmer.g_v, 97, 252)) { + break lab9; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "U")) { + return false; + } + break lab8; + } + $this.cursor = v_6; + if (! BaseStemmer$eq_s$LBaseStemmer$IS($this, 1, "y")) { + break lab7; + } + $this.ket = $this.cursor; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, GermanStemmer.g_v, 97, 252)) { + break lab7; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "Y")) { + return false; + } + } + $this.cursor = v_5; + break golab6; + } + cursor$1 = $this.cursor = v_5; + if (cursor$1 >= $this.limit) { + break lab5; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + continue replab4; + } + $this.cursor = v_4; + break replab4; + } + return true; +}; + +GermanStemmer.r_prelude$LGermanStemmer$ = GermanStemmer$r_prelude$LGermanStemmer$; + +GermanStemmer.prototype.r_mark_regions$ = function () { + var v_1; + var c; + var lab1; + var lab3; + var lab4; + var lab6; + var lab8; + var limit$0; + var cursor$0; + var cursor$1; + var $__jsx_postinc_t; + this.I_p1 = limit$0 = this.limit; + this.I_p2 = limit$0; + v_1 = cursor$0 = this.cursor; + c = (cursor$0 + 3 | 0); + if (0 > c || c > limit$0) { + return false; + } + cursor$1 = this.cursor = c; + this.I_x = cursor$1; + this.cursor = v_1; +golab0: + while (true) { + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, GermanStemmer.g_v, 97, 252)) { + break lab1; + } + break golab0; + } + if (this.cursor >= this.limit) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } +golab2: + while (true) { + lab3 = true; + lab3: + while (lab3 === true) { + lab3 = false; + if (! BaseStemmer$out_grouping$LBaseStemmer$AIII(this, GermanStemmer.g_v, 97, 252)) { + break lab3; + } + break golab2; + } + if (this.cursor >= this.limit) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + this.I_p1 = this.cursor; + lab4 = true; +lab4: + while (lab4 === true) { + lab4 = false; + if (! (this.I_p1 < this.I_x)) { + break lab4; + } + this.I_p1 = this.I_x; + } +golab5: + while (true) { + lab6 = true; + lab6: + while (lab6 === true) { + lab6 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, GermanStemmer.g_v, 97, 252)) { + break lab6; + } + break golab5; + } + if (this.cursor >= this.limit) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } +golab7: + while (true) { + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + if (! BaseStemmer$out_grouping$LBaseStemmer$AIII(this, GermanStemmer.g_v, 97, 252)) { + break lab8; + } + break golab7; + } + if (this.cursor >= this.limit) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + this.I_p2 = this.cursor; + return true; +}; + +GermanStemmer.prototype.r_mark_regions = GermanStemmer.prototype.r_mark_regions$; + +function GermanStemmer$r_mark_regions$LGermanStemmer$($this) { + var v_1; + var c; + var lab1; + var lab3; + var lab4; + var lab6; + var lab8; + var limit$0; + var cursor$0; + var cursor$1; + var $__jsx_postinc_t; + $this.I_p1 = limit$0 = $this.limit; + $this.I_p2 = limit$0; + v_1 = cursor$0 = $this.cursor; + c = (cursor$0 + 3 | 0); + if (0 > c || c > limit$0) { + return false; + } + cursor$1 = $this.cursor = c; + $this.I_x = cursor$1; + $this.cursor = v_1; +golab0: + while (true) { + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, GermanStemmer.g_v, 97, 252)) { + break lab1; + } + break golab0; + } + if ($this.cursor >= $this.limit) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } +golab2: + while (true) { + lab3 = true; + lab3: + while (lab3 === true) { + lab3 = false; + if (! BaseStemmer$out_grouping$LBaseStemmer$AIII($this, GermanStemmer.g_v, 97, 252)) { + break lab3; + } + break golab2; + } + if ($this.cursor >= $this.limit) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + $this.I_p1 = $this.cursor; + lab4 = true; +lab4: + while (lab4 === true) { + lab4 = false; + if (! ($this.I_p1 < $this.I_x)) { + break lab4; + } + $this.I_p1 = $this.I_x; + } +golab5: + while (true) { + lab6 = true; + lab6: + while (lab6 === true) { + lab6 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, GermanStemmer.g_v, 97, 252)) { + break lab6; + } + break golab5; + } + if ($this.cursor >= $this.limit) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } +golab7: + while (true) { + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + if (! BaseStemmer$out_grouping$LBaseStemmer$AIII($this, GermanStemmer.g_v, 97, 252)) { + break lab8; + } + break golab7; + } + if ($this.cursor >= $this.limit) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + $this.I_p2 = $this.cursor; + return true; +}; + +GermanStemmer.r_mark_regions$LGermanStemmer$ = GermanStemmer$r_mark_regions$LGermanStemmer$; + +GermanStemmer.prototype.r_postlude$ = function () { + var among_var; + var v_1; + var lab1; + var $__jsx_postinc_t; +replab0: + while (true) { + v_1 = this.cursor; + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + this.bra = this.cursor; + among_var = BaseStemmer$find_among$LBaseStemmer$ALAmong$I(this, GermanStemmer.a_0, 6); + if (among_var === 0) { + break lab1; + } + this.ket = this.cursor; + switch (among_var) { + case 0: + break lab1; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "y")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "u")) { + return false; + } + break; + case 3: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "a")) { + return false; + } + break; + case 4: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "o")) { + return false; + } + break; + case 5: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "u")) { + return false; + } + break; + case 6: + if (this.cursor >= this.limit) { + break lab1; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + break; + } + continue replab0; + } + this.cursor = v_1; + break replab0; + } + return true; +}; + +GermanStemmer.prototype.r_postlude = GermanStemmer.prototype.r_postlude$; + +function GermanStemmer$r_postlude$LGermanStemmer$($this) { + var among_var; + var v_1; + var lab1; + var $__jsx_postinc_t; +replab0: + while (true) { + v_1 = $this.cursor; + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + $this.bra = $this.cursor; + among_var = BaseStemmer$find_among$LBaseStemmer$ALAmong$I($this, GermanStemmer.a_0, 6); + if (among_var === 0) { + break lab1; + } + $this.ket = $this.cursor; + switch (among_var) { + case 0: + break lab1; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "y")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "u")) { + return false; + } + break; + case 3: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "a")) { + return false; + } + break; + case 4: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "o")) { + return false; + } + break; + case 5: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "u")) { + return false; + } + break; + case 6: + if ($this.cursor >= $this.limit) { + break lab1; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + break; + } + continue replab0; + } + $this.cursor = v_1; + break replab0; + } + return true; +}; + +GermanStemmer.r_postlude$LGermanStemmer$ = GermanStemmer$r_postlude$LGermanStemmer$; + +GermanStemmer.prototype.r_R1$ = function () { + return (! (this.I_p1 <= this.cursor) ? false : true); +}; + +GermanStemmer.prototype.r_R1 = GermanStemmer.prototype.r_R1$; + +function GermanStemmer$r_R1$LGermanStemmer$($this) { + return (! ($this.I_p1 <= $this.cursor) ? false : true); +}; + +GermanStemmer.r_R1$LGermanStemmer$ = GermanStemmer$r_R1$LGermanStemmer$; + +GermanStemmer.prototype.r_R2$ = function () { + return (! (this.I_p2 <= this.cursor) ? false : true); +}; + +GermanStemmer.prototype.r_R2 = GermanStemmer.prototype.r_R2$; + +function GermanStemmer$r_R2$LGermanStemmer$($this) { + return (! ($this.I_p2 <= $this.cursor) ? false : true); +}; + +GermanStemmer.r_R2$LGermanStemmer$ = GermanStemmer$r_R2$LGermanStemmer$; + +GermanStemmer.prototype.r_standard_suffix$ = function () { + var among_var; + var v_1; + var v_2; + var v_3; + var v_4; + var v_5; + var v_6; + var v_7; + var v_8; + var v_9; + var v_10; + var lab0; + var lab1; + var lab2; + var c; + var lab3; + var lab4; + var lab5; + var lab6; + var lab7; + var lab8; + var lab9; + var lab10; + var cursor$0; + var cursor$1; + var limit$0; + var cursor$2; + var cursor$3; + var cursor$4; + var cursor$5; + var cursor$6; + var cursor$7; + var limit$1; + var cursor$8; + v_1 = ((this.limit - this.cursor) | 0); + lab0 = true; +lab0: + while (lab0 === true) { + lab0 = false; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, GermanStemmer.a_1, 7); + if (among_var === 0) { + break lab0; + } + this.bra = cursor$0 = this.cursor; + if (! (! (this.I_p1 <= cursor$0) ? false : true)) { + break lab0; + } + switch (among_var) { + case 0: + break lab0; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + v_2 = ((this.limit - this.cursor) | 0); + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + this.ket = this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "s")) { + this.cursor = ((this.limit - v_2) | 0); + break lab1; + } + this.bra = this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 3, "nis")) { + this.cursor = ((this.limit - v_2) | 0); + break lab1; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + } + break; + case 3: + if (! BaseStemmer$in_grouping_b$LBaseStemmer$AIII(this, GermanStemmer.g_s_ending, 98, 116)) { + break lab0; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + } + } + cursor$2 = this.cursor = (((limit$0 = this.limit) - v_1) | 0); + v_3 = ((limit$0 - cursor$2) | 0); + lab2 = true; +lab2: + while (lab2 === true) { + lab2 = false; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, GermanStemmer.a_2, 4); + if (among_var === 0) { + break lab2; + } + this.bra = cursor$1 = this.cursor; + if (! (! (this.I_p1 <= cursor$1) ? false : true)) { + break lab2; + } + switch (among_var) { + case 0: + break lab2; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$in_grouping_b$LBaseStemmer$AIII(this, GermanStemmer.g_st_ending, 98, 116)) { + break lab2; + } + c = (this.cursor - 3 | 0); + if (this.limit_backward > c || c > this.limit) { + break lab2; + } + this.cursor = c; + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + } + } + cursor$8 = this.cursor = (((limit$1 = this.limit) - v_3) | 0); + v_4 = ((limit$1 - cursor$8) | 0); + lab3 = true; +lab3: + while (lab3 === true) { + lab3 = false; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, GermanStemmer.a_4, 8); + if (among_var === 0) { + break lab3; + } + this.bra = cursor$3 = this.cursor; + if (! (! (this.I_p2 <= cursor$3) ? false : true)) { + break lab3; + } + switch (among_var) { + case 0: + break lab3; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + v_5 = ((this.limit - this.cursor) | 0); + lab4 = true; + lab4: + while (lab4 === true) { + lab4 = false; + this.ket = this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 2, "ig")) { + this.cursor = ((this.limit - v_5) | 0); + break lab4; + } + this.bra = cursor$4 = this.cursor; + v_6 = ((this.limit - cursor$4) | 0); + lab5 = true; + lab5: + while (lab5 === true) { + lab5 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "e")) { + break lab5; + } + this.cursor = ((this.limit - v_5) | 0); + break lab4; + } + cursor$5 = this.cursor = ((this.limit - v_6) | 0); + if (! (! (this.I_p2 <= cursor$5) ? false : true)) { + this.cursor = ((this.limit - v_5) | 0); + break lab4; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + } + break; + case 2: + v_7 = ((this.limit - this.cursor) | 0); + lab6 = true; + lab6: + while (lab6 === true) { + lab6 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "e")) { + break lab6; + } + break lab3; + } + this.cursor = ((this.limit - v_7) | 0); + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 3: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + v_8 = ((this.limit - this.cursor) | 0); + lab7 = true; + lab7: + while (lab7 === true) { + lab7 = false; + this.ket = this.cursor; + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + v_9 = ((this.limit - this.cursor) | 0); + lab9 = true; + lab9: + while (lab9 === true) { + lab9 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 2, "er")) { + break lab9; + } + break lab8; + } + this.cursor = ((this.limit - v_9) | 0); + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 2, "en")) { + this.cursor = ((this.limit - v_8) | 0); + break lab7; + } + } + this.bra = cursor$6 = this.cursor; + if (! (! (this.I_p1 <= cursor$6) ? false : true)) { + this.cursor = ((this.limit - v_8) | 0); + break lab7; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + } + break; + case 4: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + v_10 = ((this.limit - this.cursor) | 0); + lab10 = true; + lab10: + while (lab10 === true) { + lab10 = false; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, GermanStemmer.a_3, 2); + if (among_var === 0) { + this.cursor = ((this.limit - v_10) | 0); + break lab10; + } + this.bra = cursor$7 = this.cursor; + if (! (! (this.I_p2 <= cursor$7) ? false : true)) { + this.cursor = ((this.limit - v_10) | 0); + break lab10; + } + switch (among_var) { + case 0: + this.cursor = ((this.limit - v_10) | 0); + break lab10; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + } + } + break; + } + } + this.cursor = ((this.limit - v_4) | 0); + return true; +}; + +GermanStemmer.prototype.r_standard_suffix = GermanStemmer.prototype.r_standard_suffix$; + +function GermanStemmer$r_standard_suffix$LGermanStemmer$($this) { + var among_var; + var v_1; + var v_2; + var v_3; + var v_4; + var v_5; + var v_6; + var v_7; + var v_8; + var v_9; + var v_10; + var lab0; + var lab1; + var lab2; + var c; + var lab3; + var lab4; + var lab5; + var lab6; + var lab7; + var lab8; + var lab9; + var lab10; + var cursor$0; + var cursor$1; + var limit$0; + var cursor$2; + var cursor$3; + var cursor$4; + var cursor$5; + var cursor$6; + var cursor$7; + var limit$1; + var cursor$8; + v_1 = (($this.limit - $this.cursor) | 0); + lab0 = true; +lab0: + while (lab0 === true) { + lab0 = false; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, GermanStemmer.a_1, 7); + if (among_var === 0) { + break lab0; + } + $this.bra = cursor$0 = $this.cursor; + if (! (! ($this.I_p1 <= cursor$0) ? false : true)) { + break lab0; + } + switch (among_var) { + case 0: + break lab0; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + v_2 = (($this.limit - $this.cursor) | 0); + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + $this.ket = $this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "s")) { + $this.cursor = (($this.limit - v_2) | 0); + break lab1; + } + $this.bra = $this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 3, "nis")) { + $this.cursor = (($this.limit - v_2) | 0); + break lab1; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + } + break; + case 3: + if (! BaseStemmer$in_grouping_b$LBaseStemmer$AIII($this, GermanStemmer.g_s_ending, 98, 116)) { + break lab0; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + } + } + cursor$2 = $this.cursor = (((limit$0 = $this.limit) - v_1) | 0); + v_3 = ((limit$0 - cursor$2) | 0); + lab2 = true; +lab2: + while (lab2 === true) { + lab2 = false; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, GermanStemmer.a_2, 4); + if (among_var === 0) { + break lab2; + } + $this.bra = cursor$1 = $this.cursor; + if (! (! ($this.I_p1 <= cursor$1) ? false : true)) { + break lab2; + } + switch (among_var) { + case 0: + break lab2; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$in_grouping_b$LBaseStemmer$AIII($this, GermanStemmer.g_st_ending, 98, 116)) { + break lab2; + } + c = ($this.cursor - 3 | 0); + if ($this.limit_backward > c || c > $this.limit) { + break lab2; + } + $this.cursor = c; + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + } + } + cursor$8 = $this.cursor = (((limit$1 = $this.limit) - v_3) | 0); + v_4 = ((limit$1 - cursor$8) | 0); + lab3 = true; +lab3: + while (lab3 === true) { + lab3 = false; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, GermanStemmer.a_4, 8); + if (among_var === 0) { + break lab3; + } + $this.bra = cursor$3 = $this.cursor; + if (! (! ($this.I_p2 <= cursor$3) ? false : true)) { + break lab3; + } + switch (among_var) { + case 0: + break lab3; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + v_5 = (($this.limit - $this.cursor) | 0); + lab4 = true; + lab4: + while (lab4 === true) { + lab4 = false; + $this.ket = $this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 2, "ig")) { + $this.cursor = (($this.limit - v_5) | 0); + break lab4; + } + $this.bra = cursor$4 = $this.cursor; + v_6 = (($this.limit - cursor$4) | 0); + lab5 = true; + lab5: + while (lab5 === true) { + lab5 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "e")) { + break lab5; + } + $this.cursor = (($this.limit - v_5) | 0); + break lab4; + } + cursor$5 = $this.cursor = (($this.limit - v_6) | 0); + if (! (! ($this.I_p2 <= cursor$5) ? false : true)) { + $this.cursor = (($this.limit - v_5) | 0); + break lab4; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + } + break; + case 2: + v_7 = (($this.limit - $this.cursor) | 0); + lab6 = true; + lab6: + while (lab6 === true) { + lab6 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "e")) { + break lab6; + } + break lab3; + } + $this.cursor = (($this.limit - v_7) | 0); + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 3: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + v_8 = (($this.limit - $this.cursor) | 0); + lab7 = true; + lab7: + while (lab7 === true) { + lab7 = false; + $this.ket = $this.cursor; + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + v_9 = (($this.limit - $this.cursor) | 0); + lab9 = true; + lab9: + while (lab9 === true) { + lab9 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 2, "er")) { + break lab9; + } + break lab8; + } + $this.cursor = (($this.limit - v_9) | 0); + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 2, "en")) { + $this.cursor = (($this.limit - v_8) | 0); + break lab7; + } + } + $this.bra = cursor$6 = $this.cursor; + if (! (! ($this.I_p1 <= cursor$6) ? false : true)) { + $this.cursor = (($this.limit - v_8) | 0); + break lab7; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + } + break; + case 4: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + v_10 = (($this.limit - $this.cursor) | 0); + lab10 = true; + lab10: + while (lab10 === true) { + lab10 = false; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, GermanStemmer.a_3, 2); + if (among_var === 0) { + $this.cursor = (($this.limit - v_10) | 0); + break lab10; + } + $this.bra = cursor$7 = $this.cursor; + if (! (! ($this.I_p2 <= cursor$7) ? false : true)) { + $this.cursor = (($this.limit - v_10) | 0); + break lab10; + } + switch (among_var) { + case 0: + $this.cursor = (($this.limit - v_10) | 0); + break lab10; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + } + } + break; + } + } + $this.cursor = (($this.limit - v_4) | 0); + return true; +}; + +GermanStemmer.r_standard_suffix$LGermanStemmer$ = GermanStemmer$r_standard_suffix$LGermanStemmer$; + +GermanStemmer.prototype.stem$ = function () { + var v_1; + var v_2; + var v_4; + var lab0; + var lab1; + var lab2; + var lab3; + var cursor$0; + var cursor$1; + var cursor$2; + v_1 = this.cursor; + lab0 = true; +lab0: + while (lab0 === true) { + lab0 = false; + if (! GermanStemmer$r_prelude$LGermanStemmer$(this)) { + break lab0; + } + } + cursor$0 = this.cursor = v_1; + v_2 = cursor$0; + lab1 = true; +lab1: + while (lab1 === true) { + lab1 = false; + if (! GermanStemmer$r_mark_regions$LGermanStemmer$(this)) { + break lab1; + } + } + cursor$1 = this.cursor = v_2; + this.limit_backward = cursor$1; + this.cursor = this.limit; + lab2 = true; +lab2: + while (lab2 === true) { + lab2 = false; + if (! GermanStemmer$r_standard_suffix$LGermanStemmer$(this)) { + break lab2; + } + } + cursor$2 = this.cursor = this.limit_backward; + v_4 = cursor$2; + lab3 = true; +lab3: + while (lab3 === true) { + lab3 = false; + if (! GermanStemmer$r_postlude$LGermanStemmer$(this)) { + break lab3; + } + } + this.cursor = v_4; + return true; +}; + +GermanStemmer.prototype.stem = GermanStemmer.prototype.stem$; + +GermanStemmer.prototype.equals$X = function (o) { + return o instanceof GermanStemmer; +}; + +GermanStemmer.prototype.equals = GermanStemmer.prototype.equals$X; + +function GermanStemmer$equals$LGermanStemmer$X($this, o) { + return o instanceof GermanStemmer; +}; + +GermanStemmer.equals$LGermanStemmer$X = GermanStemmer$equals$LGermanStemmer$X; + +GermanStemmer.prototype.hashCode$ = function () { + var classname; + var hash; + var i; + var char; + classname = "GermanStemmer"; + hash = 0; + for (i = 0; i < classname.length; i++) { + char = classname.charCodeAt(i); + hash = (hash << 5) - hash + char; + hash = hash & hash; + } + return (hash | 0); +}; + +GermanStemmer.prototype.hashCode = GermanStemmer.prototype.hashCode$; + +function GermanStemmer$hashCode$LGermanStemmer$($this) { + var classname; + var hash; + var i; + var char; + classname = "GermanStemmer"; + hash = 0; + for (i = 0; i < classname.length; i++) { + char = classname.charCodeAt(i); + hash = (hash << 5) - hash + char; + hash = hash & hash; + } + return (hash | 0); +}; + +GermanStemmer.hashCode$LGermanStemmer$ = GermanStemmer$hashCode$LGermanStemmer$; + +GermanStemmer.serialVersionUID = 1; +$__jsx_lazy_init(GermanStemmer, "methodObject", function () { + return new GermanStemmer(); +}); +$__jsx_lazy_init(GermanStemmer, "a_0", function () { + return [ new Among("", -1, 6), new Among("U", 0, 2), new Among("Y", 0, 1), new Among("\u00E4", 0, 3), new Among("\u00F6", 0, 4), new Among("\u00FC", 0, 5) ]; +}); +$__jsx_lazy_init(GermanStemmer, "a_1", function () { + return [ new Among("e", -1, 2), new Among("em", -1, 1), new Among("en", -1, 2), new Among("ern", -1, 1), new Among("er", -1, 1), new Among("s", -1, 3), new Among("es", 5, 2) ]; +}); +$__jsx_lazy_init(GermanStemmer, "a_2", function () { + return [ new Among("en", -1, 1), new Among("er", -1, 1), new Among("st", -1, 2), new Among("est", 2, 1) ]; +}); +$__jsx_lazy_init(GermanStemmer, "a_3", function () { + return [ new Among("ig", -1, 1), new Among("lich", -1, 1) ]; +}); +$__jsx_lazy_init(GermanStemmer, "a_4", function () { + return [ new Among("end", -1, 1), new Among("ig", -1, 2), new Among("ung", -1, 1), new Among("lich", -1, 3), new Among("isch", -1, 2), new Among("ik", -1, 2), new Among("heit", -1, 3), new Among("keit", -1, 4) ]; +}); +GermanStemmer.g_v = [ 17, 65, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 32, 8 ]; +GermanStemmer.g_s_ending = [ 117, 30, 5 ]; +GermanStemmer.g_st_ending = [ 117, 30, 4 ]; + +var $__jsx_classMap = { + "src/among.jsx": { + Among: Among, + Among$SII: Among, + Among$SIIF$LBaseStemmer$B$LBaseStemmer$: Among$0 + }, + "src/stemmer.jsx": { + Stemmer: Stemmer, + Stemmer$: Stemmer + }, + "src/base-stemmer.jsx": { + BaseStemmer: BaseStemmer, + BaseStemmer$: BaseStemmer + }, + "src/german-stemmer.jsx": { + GermanStemmer: GermanStemmer, + GermanStemmer$: GermanStemmer + } +}; + + +})(JSX); + +var Among = JSX.require("src/among.jsx").Among; +var Among$SII = JSX.require("src/among.jsx").Among$SII; +var Stemmer = JSX.require("src/stemmer.jsx").Stemmer; +var BaseStemmer = JSX.require("src/base-stemmer.jsx").BaseStemmer; +var GermanStemmer = JSX.require("src/german-stemmer.jsx").GermanStemmer; diff --git a/help/de/_static/ajax-loader.gif b/help/de/_static/ajax-loader.gif new file mode 100644 index 00000000..61faf8ca Binary files /dev/null and b/help/de/_static/ajax-loader.gif differ diff --git a/help/de/_static/alert_info_32.png b/help/de/_static/alert_info_32.png new file mode 100644 index 00000000..ea4d1baf Binary files /dev/null and b/help/de/_static/alert_info_32.png differ diff --git a/help/de/_static/alert_warning_32.png b/help/de/_static/alert_warning_32.png new file mode 100644 index 00000000..a687c3dc Binary files /dev/null and b/help/de/_static/alert_warning_32.png differ diff --git a/help/de/_static/basic.css b/help/de/_static/basic.css new file mode 100644 index 00000000..c7adab45 --- /dev/null +++ b/help/de/_static/basic.css @@ -0,0 +1,665 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 59em; + max-width: 70em; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/help/de/_static/bg-page.png b/help/de/_static/bg-page.png new file mode 100644 index 00000000..fe0a6dc8 Binary files /dev/null and b/help/de/_static/bg-page.png differ diff --git a/help/de/_static/bullet_orange.png b/help/de/_static/bullet_orange.png new file mode 100644 index 00000000..1cb8097c Binary files /dev/null and b/help/de/_static/bullet_orange.png differ diff --git a/help/de/_static/comment-bright.png b/help/de/_static/comment-bright.png new file mode 100644 index 00000000..15e27edb Binary files /dev/null and b/help/de/_static/comment-bright.png differ diff --git a/help/de/_static/comment-close.png b/help/de/_static/comment-close.png new file mode 100644 index 00000000..4d91bcf5 Binary files /dev/null and b/help/de/_static/comment-close.png differ diff --git a/help/de/_static/comment.png b/help/de/_static/comment.png new file mode 100644 index 00000000..dfbc0cbd Binary files /dev/null and b/help/de/_static/comment.png differ diff --git a/help/de/_static/doctools.js b/help/de/_static/doctools.js new file mode 100644 index 00000000..0c15c009 --- /dev/null +++ b/help/de/_static/doctools.js @@ -0,0 +1,311 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var bbox = span.getBBox(); + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + var parentOfText = node.parentNode.parentNode; + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); \ No newline at end of file diff --git a/help/de/_static/documentation_options.js b/help/de/_static/documentation_options.js new file mode 100644 index 00000000..1bc8afc3 --- /dev/null +++ b/help/de/_static/documentation_options.js @@ -0,0 +1,9 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: '', + VERSION: '4.0.3', + LANGUAGE: 'de', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' +}; \ No newline at end of file diff --git a/help/de/_static/down-pressed.png b/help/de/_static/down-pressed.png new file mode 100644 index 00000000..5756c8ca Binary files /dev/null and b/help/de/_static/down-pressed.png differ diff --git a/help/de/_static/down.png b/help/de/_static/down.png new file mode 100644 index 00000000..1b3bdad2 Binary files /dev/null and b/help/de/_static/down.png differ diff --git a/help/de/_static/file.png b/help/de/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/help/de/_static/file.png differ diff --git a/help/de/_static/haiku.css b/help/de/_static/haiku.css new file mode 100644 index 00000000..75af2a5c --- /dev/null +++ b/help/de/_static/haiku.css @@ -0,0 +1,376 @@ +/* + * haiku.css_t + * ~~~~~~~~~~~ + * + * Sphinx stylesheet -- haiku theme. + * + * Adapted from http://haiku-os.org/docs/Haiku-doc.css. + * Original copyright message: + * + * Copyright 2008-2009, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Francois Revol + * Stephan Assmus + * Braden Ewing + * Humdinger + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +html { + margin: 0px; + padding: 0px; + background: #FFF url(bg-page.png) top left repeat-x; +} + +body { + line-height: 1.5; + margin: auto; + padding: 0px; + font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; + min-width: 59em; + max-width: 70em; + color: #333333; +} + +div.footer { + padding: 8px; + font-size: 11px; + text-align: center; + letter-spacing: 0.5px; +} + +/* link colors and text decoration */ + +a:link { + font-weight: bold; + text-decoration: none; + color: #dc3c01; +} + +a:visited { + font-weight: bold; + text-decoration: none; + color: #892601; +} + +a:hover, a:active { + text-decoration: underline; + color: #ff4500; +} + +/* Some headers act as anchors, don't give them a hover effect */ + +h1 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h2 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h3 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h4 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +a.headerlink { + color: #a7ce38; + padding-left: 5px; +} + +a.headerlink:hover { + color: #a7ce38; +} + +/* basic text elements */ + +div.content { + margin-top: 20px; + margin-left: 40px; + margin-right: 40px; + margin-bottom: 50px; + font-size: 0.9em; +} + +/* heading and navigation */ + +div.header { + position: relative; + left: 0px; + top: 0px; + height: 85px; + /* background: #eeeeee; */ + padding: 0 40px; +} +div.header h1 { + font-size: 1.6em; + font-weight: normal; + letter-spacing: 1px; + color: #0c3762; + border: 0; + margin: 0; + padding-top: 15px; +} +div.header h1 a { + font-weight: normal; + color: #0c3762; +} +div.header h2 { + font-size: 1.3em; + font-weight: normal; + letter-spacing: 1px; + text-transform: uppercase; + color: #aaa; + border: 0; + margin-top: -3px; + padding: 0; +} + +div.header img.rightlogo { + float: right; +} + + +div.title { + font-size: 1.3em; + font-weight: bold; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-bottom: 25px; +} +div.topnav { + /* background: #e0e0e0; */ +} +div.topnav p { + margin-top: 0; + margin-left: 40px; + margin-right: 40px; + margin-bottom: 0px; + text-align: right; + font-size: 0.8em; +} +div.bottomnav { + background: #eeeeee; +} +div.bottomnav p { + margin-right: 40px; + text-align: right; + font-size: 0.8em; +} + +a.uplink { + font-weight: normal; +} + + +/* contents box */ + +table.index { + margin: 0px 0px 30px 30px; + padding: 1px; + border-width: 1px; + border-style: dotted; + border-color: #e0e0e0; +} +table.index tr.heading { + background-color: #e0e0e0; + text-align: center; + font-weight: bold; + font-size: 1.1em; +} +table.index tr.index { + background-color: #eeeeee; +} +table.index td { + padding: 5px 20px; +} + +table.index a:link, table.index a:visited { + font-weight: normal; + text-decoration: none; + color: #dc3c01; +} +table.index a:hover, table.index a:active { + text-decoration: underline; + color: #ff4500; +} + + +/* Haiku User Guide styles and layout */ + +/* Rounded corner boxes */ +/* Common declarations */ +div.admonition { + -webkit-border-radius: 10px; + -khtml-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; + border-style: dotted; + border-width: thin; + border-color: #dcdcdc; + padding: 10px 15px 10px 15px; + margin-bottom: 15px; + margin-top: 15px; +} +div.note { + padding: 10px 15px 10px 80px; + background: #e4ffde url(alert_info_32.png) 15px 15px no-repeat; + min-height: 42px; +} +div.warning { + padding: 10px 15px 10px 80px; + background: #fffbc6 url(alert_warning_32.png) 15px 15px no-repeat; + min-height: 42px; +} +div.seealso { + background: #e4ffde; +} + +/* More layout and styles */ +h1 { + font-size: 1.3em; + font-weight: bold; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-top: 30px; +} + +h2 { + font-size: 1.2em; + font-weight: normal; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-top: 30px; +} + +h3 { + font-size: 1.1em; + font-weight: normal; + color: #0c3762; + margin-top: 30px; +} + +h4 { + font-size: 1.0em; + font-weight: normal; + color: #0c3762; + margin-top: 30px; +} + +p { + text-align: justify; +} + +p.last { + margin-bottom: 0; +} + +ol { + padding-left: 20px; +} + +ul { + padding-left: 5px; + margin-top: 3px; +} + +li { + line-height: 1.3; +} + +div.content ul > li { + -moz-background-clip:border; + -moz-background-inline-policy:continuous; + -moz-background-origin:padding; + background: transparent url(bullet_orange.png) no-repeat scroll left 0.45em; + list-style-image: none; + list-style-type: none; + padding: 0 0 0 1.666em; + margin-bottom: 3px; +} + +td { + vertical-align: top; +} + +code { + background-color: #e2e2e2; + font-size: 1.0em; + font-family: monospace; +} + +pre { + border-color: #0c3762; + border-style: dotted; + border-width: thin; + margin: 0 0 12px 0; + padding: 0.8em; + background-color: #f0f0f0; +} + +hr { + border-top: 1px solid #ccc; + border-bottom: 0; + border-right: 0; + border-left: 0; + margin-bottom: 10px; + margin-top: 20px; +} + +/* printer only pretty stuff */ +@media print { + .noprint { + display: none; + } + /* for acronyms we want their definitions inlined at print time */ + acronym[title]:after { + font-size: small; + content: " (" attr(title) ")"; + font-style: italic; + } + /* and not have mozilla dotted underline */ + acronym { + border: none; + } + div.topnav, div.bottomnav, div.header, table.index { + display: none; + } + div.content { + margin: 0px; + padding: 0px; + } + html { + background: #FFF; + } +} + +.viewcode-back { + font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; + margin: -1px -10px; + padding: 0 12px; +} + +/* math display */ +div.math p { + text-align: center; +} \ No newline at end of file diff --git a/help/de/_static/jquery-3.2.1.js b/help/de/_static/jquery-3.2.1.js new file mode 100644 index 00000000..d2d8ca47 --- /dev/null +++ b/help/de/_static/jquery-3.2.1.js @@ -0,0 +1,10253 @@ +/*! + * jQuery JavaScript Library v3.2.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2017-03-20T18:59Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.2.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Simple selector that can be filtered directly, removing non-Elements + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + // Complex selector, compare the two sets, removing non-Elements + qualifier = jQuery.filter( qualifier, elements ); + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( jQuery.isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ jQuery.camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( jQuery.camelCase ); + } else { + key = jQuery.camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( ">tbody", elem )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i, + val = 0; + + // If we already have the right measurement, avoid augmentation + if ( extra === ( isBorderBox ? "border" : "content" ) ) { + i = 4; + + // Otherwise initialize for horizontal or vertical properties + } else { + i = name === "width" ? 1 : 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with computed style + var valueIsBorderBox, + styles = getStyles( elem ), + val = curCSS( elem, name, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Fall back to offsetWidth/Height when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + if ( val === "auto" ) { + val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + } + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnothtmlwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, isFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + +
+ + +
+

Changelog

+

About the word „crash“: When reading this changelog, you might be alarmed at the number of fixes +for „crashes“. Be aware that when the word „crash“ is used here, it refers to „soft crashes“ which +don’t cause the application to quit. You simply get an error window that asks you if you want to +send the crash report to Hardcoded Software. Crashes that cause the application to quit are called +„hard crashes“ in this changelog.

+
+

4.0.3 (2016-11-24)

+
    +
  • Add new picture cache backend: shelve
  • +
  • Make shelve picture cache backend the active one on MacOS to fix #394 more +elegantly. [cocoa]
  • +
  • Remove Sparkle (auto-updates) due to technical limitations. [cocoa]
  • +
+
+
+

4.0.2 (2016-10-09)

+
    +
  • Fix systematic crash in Picture Mode under MacOS Sierra. (#394)
  • +
  • No change for Linux. Just keeping version in sync.
  • +
+
+
+

4.0.1 (2016-08-24)

+
    +
  • Add Greek localization, by Gabriel Koutilellis. (#382)
  • +
  • Fix localization base path. [qt] (#378)
  • +
  • Fix broken load results dialog. [qt]
  • +
  • Fix crash on load results. [cocoa] (#380)
  • +
  • Save preferences more predictably. [qt] (#379)
  • +
  • Fix picture mode’s fuzzy block scanner threshold. (#387)
  • +
+
+
+

4.0.0 (2016-07-01)

+
    +
  • Merge Standard, Music and Picture editions in the same application!
  • +
  • Improve documentation. (#294)
  • +
  • Add Polish, Korean, Spanish and Dutch localizations.
  • +
  • qt: Fix wrong use_regexp option propagation to core. (#295)
  • +
  • qt: Fix progress window mistakenly showing up on startup. (#357)
  • +
  • Bump Python requirement to v3.4.
  • +
  • Bump OS X requirement to 10.8
  • +
  • Drop Windows support, maybe temporarily. +Details <https://www.hardcoded.net/archive2015`#2015-11-01>`_
  • +
  • cocoa: Drop iPhoto, Aperture and iTunes support. Was unmaintained and obsolete.
  • +
  • Drop „Audio Contents“ scan type. Was confusing and seldom useful.
  • +
  • Change license to GPLv3
  • +
+
+
+

3.9.1 (2014-10-17)

+
    +
  • Fixed AttributeError: 'ComboboxModel' object has no attribute 'reset'. [Linux, Windows] (#254)
  • +
  • Fixed PermissionError on saving results. (#266)
  • +
  • Fixed a build problem introduced by Sphinx 1.2.3.
  • +
  • Updated German localisation, by Frank Weber.
  • +
+
+
+

3.9.0 (2014-04-19)

+
    +
  • This is mostly a dependencies upgrade.
  • +
  • Upgraded to Python 3.3.
  • +
  • Upgraded to Qt 5.
  • +
  • Minimum Windows version is now Windows 7 64bit.
  • +
  • Minimum Ubuntu version is now 14.04.
  • +
  • Minimum OS X version is now 10.7 (Lion).
  • +
  • … But with a couple of little improvements.
  • +
  • Improved documentation.
  • +
  • Overwrite subfolders‘ state when setting states in folder dialog (#248)
  • +
  • The error report dialog now brings the user to Github issues.
  • +
+
+
+

3.8.0 (2013-12-07)

+
    +
  • Disable symlink/hardlink deletion option when not relevant. (#247)
  • +
  • Make Cmd+A select all folders in the Folder Selection dialog. [Mac] (#228)
  • +
  • Make non-numeric delta comparison case insensitive. (#239)
  • +
  • Fix surrogate-related UnicodeEncodeError on CSV export. (#210)
  • +
  • Fixed crash on Dupe Count sorting with Delta + Dupes Only. (#238)
  • +
  • Improved documentation.
  • +
  • Important internal refactorings.
  • +
  • Dropped Ubuntu 12.04 and 12.10 support.
  • +
  • Removed the fairware dialog (More Info).
  • +
+
+
+

3.7.1 (2013-08-19)

+
    +
  • Fixed folder scan type, which was broken in v3.7.0.
  • +
+
+
+

3.7.0 (2013-08-17)

+
    +
  • Improved delta values to support non-numerical values. (#213)
  • +
  • Improved the Re-Prioritize dialog’s UI. (#224)
  • +
  • Added hardlink/symlink support on Windows Vista+. (#220)
  • +
  • Dropped 32bit support on Mac OS X.
  • +
  • Added Vietnamese localization by Phan Anh.
  • +
+
+
+

3.6.1 (2013-04-28)

+
    +
  • Improved „Make Selection Reference“ to make it clearer. (#222)
  • +
  • Improved „Open Selected“ to allow opening more than one file at once. (#142)
  • +
  • Fixed a few typos here and there. (#216 #225)
  • +
  • Tweaked the fairware dialog (More Info).
  • +
  • Added Arch Linux packaging
  • +
  • Added a 64-bit build for Windows.
  • +
  • Improved Russian localization by Kyrill Detinov.
  • +
  • Improved Brazilian localization by Victor Figueiredo.
  • +
+
+
+

3.6.0 (2012-08-08)

+
    +
  • Added „Export to CSV“. (#189)
  • +
  • Added „Replace with symlinks“ to complement „Replace with hardlinks“. [Mac, Linux] (#194)
  • +
  • dupeGuru now tells how many duplicates were affected after each re-prioritization operation. (#204)
  • +
  • Added Longest/Shortest filename criteria in the re-prioritize dialog. (#198)
  • +
  • Fixed result table cells which mistakenly became writable in v3.5.0. [Mac] (#203)
  • +
  • Fixed „Rename Selected“ which was broken since v3.5.0. [Mac] (#202)
  • +
  • Fixed a bug where „Reset to Defaults“ in the Columns menu wouldn’t refresh menu items‘ marked state.
  • +
  • Added Brazilian localization by Victor Figueiredo.
  • +
+
+
+

3.5.0 (2012-06-01)

+
    +
  • Added a Deletion Options panel.
  • +
  • Greatly improved memory usage for big scans.
  • +
  • Added a keybinding for the filter field. (#182) [Mac]
  • +
  • Upgraded minimum requirements for Ubuntu to 12.04.
  • +
+
+
+

3.4.1 (2012-04-14)

+
    +
  • Fixed the „Folders“ scan type. [Mac]
  • +
  • Fixed localization issues. [Windows, Linux]
  • +
+
+
+

3.4.0 (2012-03-29)

+
    +
  • Improved results window UI. [Windows, Linux]
  • +
  • Added a dialog to edit the Ignore List.
  • +
  • Added the ability to sort results by „marked“ status.
  • +
  • Fixed „Open with default application“. (#190)
  • +
  • Fixed a bug where there would be a false reporting of discarded matches. (#195)
  • +
  • Fixed various localization glitches.
  • +
  • Fixed hard crashes on crash reporting. (#196)
  • +
  • Fixed bug where the details panel would show up at inconvenient places in the screen. [Windows, Linux]
  • +
+
+
+

3.3.3 (2012-02-01)

+
    +
  • Fixed crash on adding some folders. [Mac OS X]
  • +
  • Added Ukrainian localization by Yuri Petrashko.
  • +
+
+
+

3.3.2 (2012-01-16)

+
    +
  • Fixed random hard crashes (yeah, again). [Mac OS X]
  • +
  • Fixed crash on Export to HTML. [Windows, Linux]
  • +
  • Added Armenian localization by Hrant Ohanyan.
  • +
  • Added Russian localization by Igor Pavlov.
  • +
+
+
+

3.3.1 (2011-12-02)

+
    +
  • Fixed a couple of nasty crashes.
  • +
+
+
+

3.3.0 (2011-11-30)

+
    +
  • Added multiple-selection in folder selection dialog for a more efficient folder removal. (#179)
  • +
  • Fixed a crash in the prioritize dialog. (#178)
  • +
  • Fixed a bug where mass marking with a filter would mark more than filtered duplicates. (#181)
  • +
  • Fixed random hard crashes. [Mac OS X] (#183 #184)
  • +
  • Added Czech localization by Aleš Nehyba.
  • +
  • Added Italian localization by Paolo Rossi.
  • +
+
+
+

3.2.1 (2011-10-02)

+
    +
  • Fixed a couple of broken action bindings from v3.2.0.
  • +
+
+
+

3.2.0 (2011-09-27)

+
    +
  • Added duplicate re-prioritization dialog. (#138)
  • +
  • Added font size preference for duplicate table. (#82)
  • +
  • Added Quicklook support. [Mac OS X] (#21)
  • +
  • Improved behavior of Mark Selected. (#139)
  • +
  • Improved filename sorting. (#169)
  • +
  • Added Chinese (Simplified) localization by Eric Dee.
  • +
  • Tweaked the fairware system.
  • +
  • Upgraded minimum requirements to OS X 10.6 and Ubuntu 11.04.
  • +
+
+
+

3.1.2 (2011-08-25)

+
    +
  • Fixed a bug preventing the Folders scan from working. (#172)
  • +
+
+
+

3.1.1 (2011-08-24)

+
    +
  • Added German localization by Gregor Tätzner.
  • +
  • Improved OS X Lion compatibility. [Mac OS X]
  • +
  • Made the file collection phase cancellable. (#168)
  • +
  • Fixed glitch in folder window upon selecting a folder state. [Windows, Linux] (#165)
  • +
  • Fixed a text coloring glitch in the results. (#156)
  • +
  • Fixed glitch in the sorting feature of the Folder column. (#161)
  • +
  • Make sure that saved results have the „.dupeguru“ extension. [Linux] (#157)
  • +
+
+
+

3.1.0 (2011-04-16)

+
    +
  • Added the „Folders“ scan type. (#89)
  • +
  • Fixed a couple of crashes. (#140 #149)
  • +
+
+
+

3.0.2 (2011-03-16)

+
    +
  • Fixed crash after removing marked dupes. (#140)
  • +
  • Fixed crash on error handling. [Windows] (#144)
  • +
  • Fixed crash on copy/move. [Windows] (#148)
  • +
  • Fixed crash when launching dupeGuru from a very long folder name. [Mac OS X] (#119)
  • +
  • Fixed a refresh bug in directory panel. (#153)
  • +
  • Improved reliability of the „Send to Trash“ operation. [Linux]
  • +
  • Tweaked Fairware reminders.
  • +
+
+
+

3.0.1 (2011-01-27)

+
    +
  • Restored the context menu which had been broken in 3.0.0. [Mac OS X] (#133)
  • +
  • Fixed a bug where an „unsaved results“ warning would be issued on quit even with empty results. (#134)
  • +
  • Removed focus from the cancel button in the progress dialog to avoid accidental cancellations. [Mac OS X] (#135)
  • +
  • Folders added through drag and drop are added to the recent folders list. (#136)
  • +
  • Added a debugging mode. (#132)
  • +
  • Fixed french localization glitches.
  • +
+
+
+

3.0.0 (2011-01-24)

+
    +
  • Re-designed the UI. (#129)
  • +
  • Internationalized dupeGuru and localized it to french. (#32)
  • +
  • Changed the format of the help file. (#130)
  • +
+
+
+

2.12.3 (2011-01-01)

+
    +
  • Fixed bug causing results to be corrupted after a scan cancellation. (#120)
  • +
  • Fixed crash when fetching Fairware unpaid hours. (#121)
  • +
  • Fixed crash when replacing files with hardlinks. (#122)
  • +
+
+
+

2.12.2 (2010-10-05)

+
    +
  • Fixed delta column colors which were broken since 2.12.0.
  • +
  • Fixed column sorting crash. (#108)
  • +
  • Fixed occasional crash during scan. (#106)
  • +
+
+
+

2.12.1 (2010-09-30)

+
    +
  • Re-licensed dupeGuru to BSD and made it Fairware.
  • +
+
+
+

2.12.0 (2010-09-26)

+
    +
  • Improved UI with a little revamp.
  • +
  • Added the possibility to place hardlinks to references after having deleted duplicates. [Mac OS X, Linux] (#91)
  • +
  • Added an option to ignore duplicates hardlinking to the same file. [Mac OS X, Linux] (#92)
  • +
  • Added multiple selection in the „Add Directory“ dialog. [Mac OS X] (#105)
  • +
  • Fixed a bug preventing drag & drop from working in the Directories panel. [Windows, Linux]
  • +
+
+
+

2.11.1 (2010-08-26)

+
    +
  • Fixed HTML exporting which was broken in 2.11.0.
  • +
+
+
+

2.11.0 (2010-08-18)

+
    +
  • Added the ability to save results (and reload them) at arbitrary locations.
  • +
  • Improved the way reference files in dupe groups are chosen. (#15)
  • +
  • Remember size/position of all windows between launches. (#102)
  • +
  • Fixed a bug sometimes preventing dupeGuru from reloading previous results.
  • +
  • Fixed a bug sometimes causing the progress dialog to be stuck there. [Mac OS X] (#103)
  • +
  • Removed the Creation Date column, which wasn’t displaying the correct value anyway. (#101)
  • +
+
+
+

2.10.1 (2010-07-15)

+ +
+
+

2.10.0 (2010-04-13)

+
    +
  • Improved error messages when files can’t be sent to trash, moved or copied.
  • +
  • Added a custom command invocation action. (#12)
  • +
  • Filters are now applied on whole paths. (#4)
  • +
+
+
+

2.9.2 (2010-02-10)

+
    +
  • dupeGuru is now 64-bit on Mac OS X!
  • +
  • Fixed a crash upon quitting when support folder is not present. (#83)
  • +
  • Fixed a crash during sorting. (#85)
  • +
  • Fixed selection glitches, especially while renaming. (#93)
  • +
+
+
+

2.9.1 (2010-01-13)

+
    +
  • Improved memory usage for Contents scans. (#75)
  • +
  • Improved scanning speed when ref directories are involved. (#77)
  • +
  • Show a message dialog at the end of the scan if no duplicates are found. (#81)
  • +
  • Fixed a bug sometimes causing the small files threshold pref to be ignored. [Mac OS X] (#75)
  • +
+
+
+

2.9.0 (2009-11-03)

+
    +
  • Significantly improved speed and memory usage of big contents-based scans.
  • +
  • Added drag & drop support in the Directories panel. (#9)
  • +
  • Fixed a bug causing dupeGuru to be confused if a scanned file was moved during the scan. (#72)
  • +
  • Dropped support for Mac OS X 10.4 (Tiger)
  • +
+
+
+

2.8.2 (2009-10-14)

+
    +
  • Improved directory selection in the Directories panel (Windows). (#56)
  • +
  • Fixed a bug preventing dupeGuru from starting on certain machines (Windows). (#68)
  • +
  • Fixed a crash during very big scans. (#70)
  • +
+
+
+

2.8.1 (2009-10-02)

+
    +
  • Fixed crash with filtering when regular expressions were enabled. (#60)
  • +
  • Fixed crash when setting directories‘ state. (Mac OS X) (#66)
  • +
  • Fixed crash with Make Reference when certain filters are applied. (Mac OS X) (#55)
  • +
  • Improved error handling during delete/move/copy actions. (#62 #65)
  • +
+
+
+

2.8.0 (2009-09-07)

+
    +
  • Added support for all kinds of bundle (not just applications) (Mac OS X) (#11)
  • +
  • Re-introduced the Export to XHTML feature to Windows. (#14)
  • +
  • Improved Export to XHTML speed. (#14)
  • +
  • Improved Contents scanning speed for large files. (#33)
  • +
  • Improved the grouping algorithm to reduce the number of discarded files in non-exact scans. (#51)
  • +
  • Stopped showing the same file on the 2 sides of the details panel when a ref file is selected. (#50)
  • +
  • Fixed crashes in the Directories panel. (#46)
  • +
+
+
+

2.7.3 (2009-06-20)

+
    +
  • +
    Fixed bugs with selection being jumpy during „Make Reference“ actions and Power Marker
    +
    switches. (#3)
    +
    +
  • +
  • Fixed crash happening when a file with non-roman characters couldn’t be analyzed. (#30)
  • +
  • Fixed crash sometimes happening during the file collection phase in scanning. (#38)
  • +
  • Restored double-click and right-click behavior lost in the PyQt move (Windows). (#34 #35)
  • +
+
+
+

2.7.2 (2009-06-10)

+
    +
  • Fixed an occasional crash on Copy/Move operations. (#16)
  • +
  • Added automatic exclusion for sensible folders (like system folders). (#20)
  • +
  • Fixed an occasional crash when application files were part of the results (Mac OS X). (#25)
  • +
+
+
+

2.7.1 (2009-05-29)

+
    +
  • Fixed a bug causing crashes when having application files in the results.
  • +
  • Fixed a bug causing a GUI freeze at the beginning of a scan with a lot of files.
  • +
  • Fixed a bug that sometimes caused a crash when an action was cancelled, and then started again.
  • +
+
+
+

2.7.0 (2009-05-25)

+
    +
  • Converted the Windows GUI to Qt.
  • +
  • Improved the reliability of the scanning process.
  • +
+
+
+

2.6.1 (2009-03-27)

+
    +
  • Fixed an occasional crash caused by permission issues.
  • +
  • +
    Fixed a bug where the „X discarded“ notice would show a too large number of discarded
    +
    duplicates.
    +
    +
  • +
+
+
+

2.6.0 (2008-09-10)

+
    +
  • Added a small file threshold preference.
  • +
  • Added a notice in the status bar when matches were discarded during the scan.
  • +
  • Improved duplicate prioritization (smartly chooses which file you will keep).
  • +
  • Improved scan progress feedback.
  • +
  • Improved responsiveness of the user interface for certain actions.
  • +
+
+
+

2.5.4 (2008-08-10)

+
    +
  • Improved the speed of results loading and saving.
  • +
  • Fixed a crash sometimes occurring during duplicate deletion.
  • +
+
+
+

2.5.3 (2008-07-08)

+
    +
  • Improved unicode handling for filenames. dupeGuru will now find a lot more duplicates if your files have non-ascii characters in it.
  • +
  • Fixed „Clear Ignore List“ crash in Windows.
  • +
+
+
+

2.5.2 (2008-01-10)

+
    +
  • Improved the handling of low memory situations.
  • +
  • Improved the directory panel. The „Remove“ button changes to „Put Back“ when an excluded directory is selected.
  • +
  • Improved scan, delete and move speed in situations where there were a lot of duplicates.
  • +
  • Fixed occasional crashes when moving bundles (such as .app files).
  • +
  • Fixed occasional crashes when moving a lot of files at once.
  • +
+
+
+

2.5.1 (2007-11-22)

+
    +
  • Added the „Remove empty folders“ option.
  • +
  • Fixed results load/save issues.
  • +
  • Fixed occasional status bar inaccuracies when the results are filtered.
  • +
+
+
+

2.5.0 (2007-09-15)

+
    +
  • Added post scan filtering.
  • +
  • Fixed issues with the rename feature under Windows
  • +
  • Fixed some user interface annoyances under Windows
  • +
+
+
+

2.4.8 (2007-04-14)

+
    +
  • Improved UI responsiveness (using threads) under Mac OS X.
  • +
  • Improved result load/save speed and memory usage.
  • +
+
+
+

2.4.7 (2007-03-10)

+
    +
  • Fixed a „bad file descriptor“ error occasionally popping up.
  • +
  • Fixed a bug with non-latin directory names.
  • +
+
+
+

2.4.6 (2007-02-10)

+
    +
  • Added Re-orderable columns. In fact, I re-added the feature which was lost in the C# conversion in 2.4.0 (Windows).
  • +
  • Changed the behavior of the scanning engine when setting the hardness to 100. It will now only match files that have their words in the same order.
  • +
  • Fixed a bug with all the Delete/Move/Copy actions with certain kinds of files.
  • +
+
+
+

2.4.5 (2007-01-11)

+
    +
  • Fixed a bug with the Move action.
  • +
+
+
+

2.4.4 (2007-01-07)

+
    +
  • Fixed a „ghosting“ bug. Dupes deleted by dupeGuru would sometimes come back in subsequent scans (Windows).
  • +
  • Fixed bugs sometimes making dupeGuru crash when marking a dupe (Windows).
  • +
  • Fixed some minor visual glitches (Windows).
  • +
+
+
+

2.4.3 (2006-12-08)

+
    +
  • Fixed a mishandling of „.app“ files (OS X).
  • +
  • Fixed a bug preventing files from „reference“ directories to be displayed in blue in the results (Windows).
  • +
  • Fixed a bug preventing some files to be sent to the recycle bin (Windows).
  • +
  • Fixed a bug in the packaging preventing certain Windows configurations to start dupeGuru at all.
  • +
+
+
+

2.4.2 (2006-11-18)

+
    +
  • Fixed a bug with directory states.
  • +
+
+
+

2.4.1 (2006-11-15)

+
    +
  • Fixed a bug causing the ignore list not to be saved.
  • +
  • Fixed a bug sometimes making delete and move operations stall.
  • +
+
+
+

2.4.0 (2006-11-10)

+
    +
  • Changed the Windows interface. It is now .NET based.
  • +
  • Added an auto-update feature to the windows version.
  • +
  • Changed the way power marking works. It is now a mode instead of a separate window.
  • +
  • Changed the „Size (MB)“ column for a „Size (KB)“ column. The values are now „ceiled“ instead of rounded. Therefore, a size „0“ is now really 0 bytes, not just a value too small to be rounded up. It is also the case for delta values.
  • +
  • Removed the min word length/count options. These came from Mp3 Filter, and just aren’t used anymore. Word weighting does pretty much the same job.
  • +
+
+
+

2.3.4 (2006-11-07)

+
    +
  • Improved speed and memory usage of the scanning engine, again. Does it mean there was a lot of improvements to be made? Nah…
  • +
+
+
+

2.3.3 (2006-11-02)

+
    +
  • Improved speed and memory usage of the scanning engine, especially when the scan results in a lot of duplicates.
  • +
  • Now I wonder if Sparkle is going to work well…
  • +
+
+
+

2.3.2 (2006-10-16)

+
    +
  • Added an auto-update feature in the Mac OS X version (with Sparkle).
  • +
  • Fixed a bug preventing some duplicate reports to be created correctly under Windows.
  • +
+
+
+

2.3.1 (2006-10-02)

+
    +
  • Fixed a bug preventing some duplicates to be found, especially when scanning lots of files.
  • +
+
+
+

2.3.0 (2006-09-22)

+
    +
  • Added XHTML export feature.
  • +
+
+
+

2.2.10 (2006-08-31)

+
    +
  • Added sticky columns.
  • +
  • Fixed an issue with file caching between scans.
  • +
  • Fixed an issue preventing some duplicates from being deleted/moved/copied.
  • +
+
+
+

2.2.9 (2006-08-27)

+
    +
  • Fixed an issue with ignore list and unicode.
  • +
  • Fixed an issue with file attribute fetching sometimes causing dupeGuru to crash.
  • +
  • Fixed an issue in the directories panel under Windows.
  • +
+
+
+

2.2.8 (2006-08-17)

+
    +
  • Fixed an issue in the duplicate seeking engine preventing some duplicates to be found.
  • +
+
+
+

2.2.7 (2006-08-12)

+
    +
  • Improved unicode support.
  • +
  • Improved the „Reveal in Finder“ („Open Containing Folder“ in Windows) feature so it selects the file in the folder it opens.
  • +
+
+
+

2.2.6 (2006-08-07)

+
    +
  • Improved the ignore list system.
  • +
  • dupeGuru is now a Universal application on Mac OS X.
  • +
+
+
+

2.2.5 (2006-07-26)

+
    +
  • Improved application (.app) dupe detection on Mac OS X.
  • +
  • Fixed an issue that occasionally made dupeGuru crash on startup.
  • +
+
+
+

2.2.4 (2006-06-27)

+
    +
  • Fixed an issue with Move and Copy features.
  • +
+
+
+

2.2.3 (2006-06-15)

+
    +
  • Improved duplicate scanning speed.
  • +
  • Added a warning that a file couldn’t be renamed if a file with the same name already exists.
  • +
+
+
+

2.2.2 (2006-06-07)

+
    +
  • Added „Rename Selected“ feature.
  • +
  • Fixed some minor issues with „Reload Last Results“ feature.
  • +
  • Fixed ignore list issues.
  • +
+
+
+

2.2.1 (2006-05-22)

+
    +
  • Fixed occasional progress bar woes under Windows.
  • +
  • Fixed a bug in the registration system under Windows.
  • +
  • Nothing has been changed in the Mac OS X version, but I want to keep version in sync.
  • +
+
+
+

2.2.0 (2006-05-10)

+
    +
  • Added destination path re-creation options.
  • +
  • Added an ignore list.
  • +
  • Changed the main icon.
  • +
  • Improved dramatically the delta values feature.
  • +
+
+
+

2.1.2 (2006-04-18)

+
    +
  • Added the „Match similar words“ option.
  • +
  • Fixed Power marking issues under Mac.
  • +
+
+
+

2.1.1 (2006-04-14)

+
    +
  • Added the „Display delta values“ option.
  • +
  • Improved Power marking sorting speed under Mac.
  • +
  • Fixed Power marking sorting issues.
  • +
+
+
+

2.1.0 (2006-04-03)

+
    +
  • Added the Power Marker feature.
  • +
  • Fixed a column sorting bug. The results would sometimes lose their sort order.
  • +
  • Fixed a bug with the Make Reference feature. The results sometimes wasn’t correctly refreshed after the reference switch.
  • +
+
+
+

2.0.1 (2006-03-23)

+
    +
  • Fixed an issue occasionally occurring when trying to reload results from removable media that is no longer present.
  • +
+
+
+

2.0.0 (2006-03-17)

+
    +
  • Complete rewrite.
  • +
  • Now runs on Mac OS X.
  • +
+
+
+

1.0.0 (2004-09-24)

+
    +
  • Initial release.
  • +
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/de/faq.html b/help/de/faq.html new file mode 100644 index 00000000..31728dbd --- /dev/null +++ b/help/de/faq.html @@ -0,0 +1,104 @@ + + + + + + + + Häufig gestellte Fragen — dupeGuru 4.0.3 Dokumentation + + + + + + + + + + + + + + +
+ + +
+

Häufig gestellte Fragen

+
+

What is dupeGuru?

+
+
+

Was macht es besser ala andere Duplikatscanner?

+

Die Scan-Engine ist extrem flexibel. Sie können sie modifizieren, um die Art von Ergebnissen zu bekommen die Sie möchten. Sie können mehr über die dupeGuru Modifikationen finden auf der Einstellungen Seite.

+
+
+

Wie sicher ist dupeGuru?

+

Sehr sicher. DupeGuru wurde entwickelt, um sicherzustellen keine Dateien zu löschen, die nicht gelöscht werden sollen. Erstens, es existiert ein Referenzordnersystem welches Ordner definiert, die auf keinen Fall angefasst werden sollen. Dann gibt es noch das Referenzgruppensystem, das sicherstellt das immer ein Mitglied einer Duplikatgruppe behalten wird.

+
+
+

Was sind die Demo-Einschränkungen von dupeGuru?

+

Keine, dupeGuru ist Fairware.

+
+
+

Die Markierungsbox einer Datei, die ich löschen möchte, ist deaktiviert. Was muss ich tun?

+

Sie können die Referenz nicht markieren (die erste Datei einer Duplikatgruppe). Wie auch immer, Sie können ein Duplikat zur Referenz befördnern. Wenn eine Datei, die Sie markieren möchten, eine Referenz ist, muss ein Duplikat der Gruppe zur Referenz gemacht werden, indem man es auswählt und auf Aktionen–>Mache Ausgewählte zur Referenz gehen. Befindet sich die Referenzdatei in einem Referenzordner (Dateiname in blauen Buchstaben), kann sie nicht aus der Referenzposition entfernt werden.

+
+
+

ich habe einen Ordner aus dem ich wirklich nichts löschen möchte.

+

Möchten Sie sicherstellen, das dupeGuru niemals Dateien aus einem bestimmten Ordner löscht, dann versetzen sie den Ordner in den Referenzzustand. Siehe Ordnerauswahl.

+
+
+

Was bedeutet diese ‚(X verworfen)‘ Nachricht in der Statusbar?

+

In einigen Fällen werden manche Treffer aus Sicherheitsgründen nicht in den Ergebnissen angezeigt. Lassen Sie mich ein Beispiel konstruieren. Wir haben 3 Datein: A, B und C. Wir scannen sie mit einer niedrigen Filterempfindlichkeit. Der Scanner findet heraus das A mit B und C übereinstimmt, aber B nicht mit C übereinstimmt. Hier hat dupeGuru ein Problem. Es kann keine Duplikatgruppe erstellen mit A, B und C, weil nicht alle Dateien der Gruppe zusammenpassen. Es könnte 2 Gruppen erstellen: eine A-B Gruppe und eine A-C Gruppe, aber es dies aus Sicherheitsbedenken nicht tun. Denken wir darüber nach: Wenn B nicht zu C passt, heißt das, das entweder B oder C keine echten Duplikate sind. Wären es 2 Gruppen (A-B und A-C), würden Sie damit enden sowohl B als auch C zu löschen. Und ist keine der Beiden ein Duplikat, möchten Sie das ganz sicher nicht tun, richtig? Also verwirft dupeGuru in diesem Fall den A-C Treffer (und fügt eine Notiz in der Statusbar hinzu). Folglich, wenn Sie B löschen und den Scan erneut durchführen, haben Sie einen A-C Treffer nächstes Mal in den Ergebnissen.

+
+
+

Ich möchte alle Dateien aus einem bestimmten Ordner markieren. Was kann ich tun?

+

Aktiveren Sie den Nur Duplikate Modus und klicken auf die Ordnerspalte, um die Duplikate nach Ordner zu sortieren. Es wird dann einfach sein, alle Duplikate aus dem selben Ordner auszuwählen und auf die Leertaste zu drücken, um sie alle zu markieren.

+
+
+

Ich habe versucht, meine Duplikate in den Mülleimer zu verschieben, aber dupeGuru sagt es ist nicht möglich. Warum? Was kann ich tun?

+

Meistens kann dupeGuru aufgrund von Dateirechten keine Dateien in den Mülleimer schicken. Sie brauchen Schreib Rechte für Dateien, die in den Mülleimer sollen. Wenn Sie nicht vertraut mit Kommandozeilenwerkzeugen sind, können dafür auch Dienstprogramme wie BatChmod verwendet werden, um die Dateirechte zu reparieren.

+

Wenn dupeGuru sich nach dem Reparieren der Recht immer noch verweigert, könnte es helfen die Funktion „Verschiebe Markierte nach…“ als Workaround zu verwenden. Anstelle die Dateien in den Mülleimer zu schieben, senden SIe sie in einen temporären Ordner, den Sie dann manuell löschen können.

+

Wenn dies alles fehlschlägt, kontaktieren Sie HS support, wir werden das Problem lösen.

+
+
+

Zu tun

+

This FAQ qestion is outdated, see english version.

+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/de/folders.html b/help/de/folders.html new file mode 100644 index 00000000..68a845d2 --- /dev/null +++ b/help/de/folders.html @@ -0,0 +1,81 @@ + + + + + + + + Ordnerauswahl — dupeGuru 4.0.3 Dokumentation + + + + + + + + + + + + + + +
+ + +
+

Ordnerauswahl

+

Das erste Fenster das Sie sehen, wenn dupeGuru gestartet wird, ist das Ordnerauswahl Fenster. Dieses Fenster enthält die Liste der Ordner die durchsucht werden, wenn Sie Scan wählen.

+

Das Fenster ist leicht zu bedienen. Wollen Sie einen Ordner hinzufügen, klicken Sie auf den + Knopf. Haben Sie bereits vorher Ordner hinzugefügt, erscheint ein Popup-Menü mit einer Liste der zuletzt hinzugefügten Ordner. Sie können einen davon auswählen, indem Sie darauf klicken. Wenn Sie auf den ersten Eintrag der Liste klicken, Neuen Ordner hinzufügen…, werden Sie nach einem Ordner zum Hinzufügen gefragt. Nutzen Sie dupeGuru zum ersten Mal, erscheint kein Menü und Sie werden direkt nach einem Ordner gefragt. Ein alternativer Weg zum Hinzufügen der Ordner ist, sie auf die Liste zu ziehen.

+

Um einen Ordner zu entfernen, wählen Sie ihn aus und klicken auf -. Wenn Sie einen Unterordner auswählen, wird der ausgewählte Ordner in den Ausgeschlossen Zustand versetzt (siehe unten), anstatt entfernt zu werden.

+
+

Ordnerzustände

+

Jeder Ordner kann in einem von 3 Zuständen sein:

+
    +
  • Normal: Duplikate in diesem Ordner können gelöscht werden.
  • +
  • Referenz: Duplikate in diesem Ordner können nicht gelöscht werden. Dateien dieses Ordners können sich nur in der Referenz Position einer Duplikatgruppe befinden. Ist mehr als eine Datei des Referenzordners in derselben Duplikatgruppe, so wird nur Eine behalten. Die Anderen werden aus der Gruppe entfernt.
  • +
  • Ausgeschlossen: Dateien in diesem Verzeichnis sind nicht im Scan eingeschlossen.
  • +
+

Der Standardzustand eines Ordners ist natürlich Normal. Sie können den Referenz Zustand für Ordner nutzen, in denen auf keinen Fall eine Datei gelöscht werden soll.

+

Wenn sie einen Zustand für ein Verzeichnis setzen, erben alle Unterordner automatisch diesen Zustand, es sei denn Sie ändern den Zustand der Unterordner explizit.

+
+

Zu tun

+

Add iPhoto/Aperture/iTunes libraries notes

+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/de/genindex.html b/help/de/genindex.html new file mode 100644 index 00000000..e4584da1 --- /dev/null +++ b/help/de/genindex.html @@ -0,0 +1,57 @@ + + + + + + + + + Stichwortverzeichnis — dupeGuru 4.0.3 Dokumentation + + + + + + + + + + + + +
+ + + +

Stichwortverzeichnis

+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/de/index.html b/help/de/index.html new file mode 100644 index 00000000..a52f7368 --- /dev/null +++ b/help/de/index.html @@ -0,0 +1,92 @@ + + + + + + + + dupeGuru Hilfe — dupeGuru 4.0.3 Dokumentation + + + + + + + + + + + + + +
+ + +
+

dupeGuru Hilfe

+

Obwohl dupeGuru auch leicht ohne Dokumentation genutzt werden kann, ist es sinnvoll die Hilfe zu lesen. Wenn Sie nach einer Führung für den ersten Duplikatscan suchen, werfen Sie einen Blick auf die Schnellstart Sektion

+

Es ist eine gute Idee dupeGuru aktuell zu halten. Sie können die neueste Version auf der homepage finden.

+

Inhalte:

+ +
+
+

Indices and tables

+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/de/objects.inv b/help/de/objects.inv new file mode 100644 index 00000000..f1a405d4 Binary files /dev/null and b/help/de/objects.inv differ diff --git a/help/de/preferences.html b/help/de/preferences.html new file mode 100644 index 00000000..96797ed6 --- /dev/null +++ b/help/de/preferences.html @@ -0,0 +1,80 @@ + + + + + + + + Einstellungen — dupeGuru 4.0.3 Dokumentation + + + + + + + + + + + + + + +
+ + +
+

Einstellungen

+

Dateitypen dürfen gemischt werden: Wird diese Box gewählt, dürfen Duplikategruppen Bilder mit unterschiedlichen Dateierweiterungen enthalten.

+

Ignoriere Duplikate die mit derselben Datei verlinkt sind: Ist diese Option aktiviert, wird dupeGuru überprüfen ob Duplikate auf den selben inode verweisen. Wenn sie es tun, werden sie nicht als Duplikat erkannt. (Nur für OS X und Linux)

+

Nutze reguläre Ausdrücke beim Filtern: Ist diese Option aktiviert, wird die Filterfunktion Ihre Filteranfrage als regulären Ausdruck interpretieren. Sie zu erklären ist außerhalb des Aufgabenbereiches dieser Dokumentation. Ein guter Platz zum Starten ist regular-expressions.info.

+

Entferne leere Ordner nach dem Löschen oder Verschieben: Ist diese Option aktiviert, werden Ordner gelöscht nachdem eine Datei gelöscht oder verschoben wurde und der Ordner leer ist.

+

Copy and Move: Determines how the Copy and Move operations (in the Action menu) will behave.

+
    +
  • Zum Ziel: Alle Dateien werden direkt in das ausgwählte Verzeichnis gesendet, ohne zu versuchen den Quellpfad wiederherzustellen
  • +
  • Relativen Pfad neu erstellen: Der Pfad der Quelldatei wird im Zielverzeichnis wiederhergestellt bis zur Wurzelauswahl im Verzeichnis Panel. Zum Beispiel, wenn Sie /Users/foobar/SomeFolder zu ihrem Verzeichnis Panel hinzufügen und /Users/foobar/SomeFolder/SubFolder/SomeFile.ext zu dem Ziel /Users/foobar/MyDestination verschieben, wird das endgültige Ziel der Datei /Users/foobar/MyDestination/SubFolder sein (SomeFolder wurde vom Pfad der Quelldatei im endgültigen Ziel abgetrennt.).
  • +
  • Absoluten Pfad neu erstellen: Der Pfad der Quelldatei wird im Zielverzeichnis vollständig wiederhergestellt. Zum Beispiel, wenn Sie /Users/foobar/SomeFolder/SubFolder/SomeFile.ext zu dem Ziel /Users/foobar/MyDestination verschieben, wird das endgültige Ziel der Datei /Users/foobar/MyDestination/Users/foobar/SomeFolder/SubFolder sein.
  • +
+

Auf jeden Fall behandelt dupeGuru Namenskonflikte indem es dem Ziel-Dateinamen eine Nummer voranstellt, wenn der Dateiname bereits im Zielverzeichnis existiert.

+

Eigener Befehl: Diese Einstellung bestimmt den Befehl der durch „Führe eigenen Befehl aus“ ausgeführt wird. Sie können jede externe Anwendung durch diese Aktion aufrufen. Dies ist zum Beispiel hilfreich, wenn Sie eine gute diff-Anwendung installiert haben.

+

Das Format des Befehls ist das Selbe wie in einer Befehlszeile, außer das 2 Platzhalter vorhanden sind: %d und %r. Diese Platzhalter werden durch den Pfad des markierten Duplikates (%d) und dem Pfad der Duplikatereferenz ersetzt (%r).

+

Wenn der Pfad Ihrer ausführbaren Datei Leerzeichen enthält, so schließen sie ihn bitte mit „“ Zeichen ein. Sie sollten auch Platzhalter mit den Zitatzeichen einschließen, denn es ist möglich, das die Pfade der Duplikate und Referenzen ebenfalls Leerzeichen enthalten. Hier ist ein Beispiel eines eigenen Befehls:

+
"C:\Program Files\SuperDiffProg\SuperDiffProg.exe" "%d" "%r"
+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/de/quick_start.html b/help/de/quick_start.html new file mode 100644 index 00000000..5f08bd2a --- /dev/null +++ b/help/de/quick_start.html @@ -0,0 +1,74 @@ + + + + + + + + Schnellstart — dupeGuru 4.0.3 Dokumentation + + + + + + + + + + + + + + +
+ + +
+

Schnellstart

+

Damit Sie sich schnell mit dupeGuru zurechtfinden, machen wir für den Anfang einen Standardscan mit den Voreinstellungen.

+
    +
  • dupeGuru starten.
  • +
  • Zu scannende Ordner entweder mit drag & drop oder dem „+“ Knopf auswählen.
  • +
  • Drücken Sie auf Scan.
  • +
  • Warten Sie bis der Scanvorgang fertig ist.
  • +
  • Betrachten Sie jedes Duplikat (die eingerückten Dateien) und überprüfen ob es wirklich ein Duplikat der Referenzdatei ist (die obere nicht eingerückte Datei ohne Markierungsfeld).
  • +
  • Wenn eine Datei kein Duplikat ist, wählen Sie es aus und drücken auf Aktionen–>Entferne Ausgewählte aus den Ergebnissen.
  • +
  • Erst wenn Sie sicher sind, das keine Falsch-Duplikate mehr in den Ergebnissen sind, drücken Sie auf Bearbeiten–>Alle markieren, und dann Aktionen–>Verschiebe Markierte in den Mülleimer.
  • +
+

Das war nur ein einfacher Scan. Es gibt viele Optionen mit denen der Suchdurchlauf beeinflusst werden und einige Methoden zur Begutachtung und Veränderung der Ergebnisliste. Um mehr über sie zu erfahren, lesen Sie die restlichen Hilfedateien.

+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/de/reprioritize.html b/help/de/reprioritize.html new file mode 100644 index 00000000..da83f35f --- /dev/null +++ b/help/de/reprioritize.html @@ -0,0 +1,82 @@ + + + + + + + + Re-Prioritizing duplicates — dupeGuru 4.0.3 Dokumentation + + + + + + + + + + + + + + +
+ + +
+

Re-Prioritizing duplicates

+

dupeGuru tries to automatically determine which duplicate should go in each group’s reference +position, but sometimes it gets it wrong. In many cases, clever dupe sorting with „Delta Values“ +and „Dupes Only“ options in addition to the „Make Selected into Reference“ action does the trick, but +sometimes, a more powerful option is needed. This is where the Re-Prioritization dialog comes into +play. You can summon it through the „Re-Prioritize Results“ item in the „Actions“ menu.

+

This dialog allows you to select criteria according to which a reference dupe will be selected in +each dupe group. The list of available criteria is on the left and the list of criteria you’ve +selected is on the right.

+

A criteria is a category followed by an argument. For example, „Size (Highest)“ means that the dupe +with the biggest size will win. „Folder (/foo/bar)“ means that dupes in this folder will win. To add +a criterion to the rightmost list, first select a category in the combobox, then select a +subargument in the list below, and then click on the right pointing arrow button.

+

The order of the list on the right is important (you can re-order items through drag & drop). When +picking a dupe for reference position, the first criterion is used. If there’s a tie, the second +criterion is used and so on and so on. For example, if your arguments are „Size (Highest)“ and then +„Filename (Doesn’t end with a number)“, the reference file that will be picked in a group will be +the biggest file, and if two or more files have the same size, the one that has a filename that +doesn’t end with a number will be used. When all criteria result in ties, the order in which dupes +previously were in the group will be used.

+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/de/results.html b/help/de/results.html new file mode 100644 index 00000000..55755312 --- /dev/null +++ b/help/de/results.html @@ -0,0 +1,151 @@ + + + + + + + + Ergebnisse — dupeGuru 4.0.3 Dokumentation + + + + + + + + + + + + + + +
+ + +
+

Ergebnisse

+

Sobald dupeGuru den Duplikatescan beendet hat, werden die Ergebnisse in Form einer Duplikate-Gruppenliste gezeigt.

+
+

Über Duplikatgruppen

+

Eine Duplikatgruppe ist eine Gruppe von übereinstimmenden Dateien. Jede Gruppe hat eine Referenzdatei und ein oder mehrere Duplikate. Die Referenzdatei ist die 1. Datei der Gruppe. Die Auswahlbox ist deaktiviert. Darunter befinden sich die eingerückten Duplikate.

+

Sie können Duplikate markieren, aber niemals die Referenzdatei der Gruppe. Das ist eine Sicherheitsmaßnahme, die dupeGuru davon abhält nicht nur die Duplikate zu löschen, sondern auch die Referenzdatei. Sie wollen sicher nicht das das passiert, oder?

+

Welche Dateien Referenz oder Duplikate sind hängt zuerst von ihrem Ordnerzustand ab. Eine Datei von einem Referenzordner ist immer Referenz einer Duplikatgruppe. Sind alle Dateien aus normalen Ordnern, bestimmt die Größe welche Datei die Referenz einer Gruppe sein wird. DupeGuru nimmt an, das Sie immer die größte Datei behalten wollen. Also übernimmt die größte Datei die Referenzposition.

+

Sie können die Referenzdatei manuell verändern. Um das zu tun, wählen Sie das Duplikat aus, das zur Referenz befördert werden soll und drücken auf Aktionen–>Mache Ausgewählte zur Referenz.

+
+
+

Ergebnisse beurteilen

+

Obwohl Sie einfach auf Markieren–>Alles markieren gehen und dann Aktionen–>Verschiebe Markierte in den Mülleimer ausführen können, um schnell alle Duplikate zu löschen, ist es sinnvoll erst alle Duplikate zu betrachten, bevor man sie löscht.

+

Um die Überprüfung zu erleichtern, können Sie das Detail Panel öffnen. Dieses Panel zeigt alle Details der gerade ausgewählten Datei sowie deren Referenz Details. Das ist sehr praktisch um schnell zu bestimmen, ob ein Duplikat wirklich ein Duplikat ist. Sie können außerdem auf die Datei doppelt klicken, um sie mit der verknüpften Anwendung zu öffnen.

+

Wenn Sie mehr Falschpositive als echte Duplikate haben (die Filterempfindlichkeit sehr niedrig ist), ist es der beste Weg die echten Duplikate zu markieren und mit Aktionen–>Verschiebe Markierte in den Mülleimer zu entfernen. Haben Sie mehr echte Duplikate als Falschpositive, können Sie stattdessen alle unechten Duplikate markieren und Entferne Markierte aus den Ergebnissen nutzen.

+
+
+

Markierung und Auswahl

+

Ein markiertes Duplikat ist ein Duplikat, dessen kleine Box ein Häkchen hat. Ein ausgewähltes Duplikat ist hervorgehoben. Mehrfachauswahl wird in dupeGuru über den normalen Weg erreicht (Shift/Command/Steuerung Klick). Sie können die Markierung aller Duplikate umschalten, indem sie Leertaste drücken.

+
+

Zu tun

+

Add „Non-numerical delta“ information.

+
+
+
+

Nur Duplikate anzeigen

+

Wird dieser Modus aktiviert, so werden ausschließlich Duplikate ohne ihre respektive Referenzdatei gezeigt. Sie können diese Liste auswählen, markieren und sortieren, ganz wie im normalen Modus.

+

Die dupeGuru Ergebnisse werden, im normalen Modus, nach der Referenzdatei der Duplikatgruppen sortiert. Das bedeutet zum Beispiel, um alle Duplikate mit der „exe“ Erweiterung zu markieren, können Sie nicht einfach die Ergebnisse nach „Typ“ ordnen um alle exe Duplikate zu erhalten, denn eine Gruppe kann aus mehreren Typen (Dateiarten) bestehen. Hier kommt der Nur-Duplikate Modus ins Spiel. Um alle „exe“ Duplikate zu markieren, müssen Sie nur:

+
    +
  • Nur Duplikate anzeigen aktivieren
  • +
  • Die „Typ“ Spalte über das „Spalten“ Menü hinzufügen
  • +
  • Auf „Typ“ klicken, um die Liste zu sortieren
  • +
  • Das erste Duplikat mit dem „exe“ Typ lokalisieren.
  • +
  • Es auswählen.
  • +
  • Die Liste herunterscrollen und das letzte Duplikat mit dem „exe“ Typ finden.
  • +
  • Die Shift Taste halten und es auswählen.
  • +
  • Leertaste drücken, um alle ausgewählten Duplikate zu markieren.
  • +
+
+
+

Deltawerte

+

Wenn Sie diesen Schalter aktivieren, zeigen einige Spalten den Wert relativ zur Duplikate-Referenz anstelle des absoluten Wertes an. Diese Deltawerte werden zusätzlich in einer anderen Farbe dargestellt, um sie leichter zu entdecken. Zum Beispiel, ein Duplikat ist 1,2 MB groß und die Referenz 1,4 MB, dann zeigt die Größe-Spalte -0,2 MB.

+
+
+

Nur Duplikate anzeigen und Deltawerte

+

Der Nur-Duplikate Modus enthüllt seine wahre Macht nur, wenn der Deltawerte Schalter aktiviert wurde. Wenn Sie ihn anschalten, werden relative Werte anstelle Absoluter gezeigt. Wenn Sie also, zum Beispiel, alle Duplikate die mehr als 300 KB von der Referenz verschieden sind aus der Ergebnisliste entfernen möchten, so sortieren Sie die Duplikate nach der Größe, wählen alle Duplikate mit weniger als -300 in der Größe-Spalte, löschen sie und tun das selbe für Duplikate mit mehr als +300 auf der Unterseite der Liste.

+

Sie können dies außerdem nutzen, um die Referenzpriorität der Duplikateliste zu ändern. Wenn sie einen neuen Scan durchführen ist die größte Datei jeder Gruppe die Referenzdatei, solange keine Referenzordner existieren. Wollen Sie beispielsweise die Referenz nach der letztes Änderungszeit bestimmen, können Sie das Nur-Duplikate Ergebnis nach Änderungszeit in absteigender Reihenfolge sortieren, alle Duplikate mit einem Änderungszeit-Deltawert größergleich 0 auswählen und auf Mache Ausgewählte zur Referenz klicken. Der Grund warum die Sortierung absteigend erfolgen muss ist, wenn 2 Dateien der selben Duplikatgruppe ausgewählt werden und Sie Mache Ausgewählte zur Referenz klicken, dann wird nur der Erste der Liste wirklich als Referenz gesetzt. Da Sie nur die zuletzt geänderte Datei als Referenz haben möchten, stellt die vorangegangene Sortierung sicher, das der erste Eintrag der Liste auch der zuletzt Geänderte ist.

+
+
+

Filtern

+

DupeGuru unterstützt das Filtern nach dem Scandurchlauf. Damit können Sie ihre Ergebnisse einschränken und diverse Aktionen auf einer Teilmenge ausführen. Beispielsweise ist es möglich alle Duplikate, deren Dateiname „copy“ enthält mithilfe dieser Filterfunktion zu markieren.

+
+

Zu tun

+

Qt has a toolbar search field now, not a menu item.

+
+

Windows/Linux: Um diese Filterfunktion zu nutzen, klicken Sie Aktionen –> Filter anwenden, geben den Filter ein und drücken OK. Um zurück zu den ungefilterten Ergebnissen zu gelangen, gehen Sie auf Aktionen –> Filter entfernen.

+

Mac OS X: Um diese Filterfunktion zu nutzen, geben Sie ihren Filter im „Filter“ Suchfeld in der Symbolleiste ein. Um zurück zu den ungefilterten Ergebnissen zu gelangen, leeren Sie das Feld oder drücken auf „X“.

+

Im Einfach-Modus (Voreinstellung) wird jede Zeichenkette die Sie eingeben auch zum Filtern genutzt, mit Ausnahme einer Wildcard: *. Wenn Sie „[*]“ als Filter nutzen, wird alles gefunden was die eckigen Klammern [] enthält, was auch immer zwischen diesen Klammern stehen mag.

+

Für fortgeschrittenes Filtern, können Sie „Nutze reguläre Ausdrücke beim Filtern“ aktivieren. Diese Funktion erlaubt es Ihnen reguläre Ausdrücke zu verwenden. Ein regulärer Ausdruck ist ein Filterkriterium für Text. Das zu erklären sprengt den Rahmen dieses Dokuments. Ein guter Platz für eine Einführung ist regular-expressions.info.

+

Filter ignorieren, im Einfach- und RegExp-Modus, die Groß- und Kleinschreibung.

+

Damit der Filter etwas findet, muss Ihr regulärer Ausdruck nicht auf den gesamten Dateinamen passen. Der Name muss nur eine Zeichenkette enthalten die auf den Ausdruck zutrifft.

+

Sie bemerken vielleicht, das nicht alle Duplikate in Ihren gefilterten Ergebnissen auf den Filter passen. Das liegt daran, sobald ein Duplikat einer Gruppe vom Filter gefunden wird, bleiben die restlichen Duplikate der Gruppe mit in der Liste, damit Sie einen besseren Überblick über den Kontext der Duplikate erhalten. Nicht passende Duplikate bleiben allerdings im „Referenz-Modus“. Dadurch können Sie sicher sein Aktionen wie „Alles Markieren“ anzuwenden und nur gefilterte Duplikate zu markieren.

+
+
+

Aktionen Menü

+
    +
  • Ignorier-Liste leeren: Entfernt alle ignorierten Treffer die Sie hinzugefügt haben. Um wirksam zu sein, muss ein neuer Scan für die gerade gelöschte Ignorier-Liste gestartet werden.
  • +
  • Exportiere als XHTML: Nimmt die aktuellen Ergebnisse und erstellt aus ihnen eine XHTML Datei. Die Spalten die sichtbar werden, wenn sie auf diesen Knopf drücken, werden die Spalten in der XHTML Datei sein. Die Datei wird automatisch mit dem Standardbrowser geöffnet.
  • +
  • Verschiebe Markierte in den Mülleimer: Verschiebt alle markierten Duplikate in den Mülleimer.
  • +
  • Lösche Markierte und ersetze mit Hardlinks: Verschiebt alle Markierten in den Mülleimer. Danach werden die gelöschten Dateien jedoch mit Hardlinks zur Referenzdatei ersetzt hard link . (Nur OS X und Linux)
  • +
  • Verschiebe Markierte nach…: Fragt nach einem Ziel und verschiebt alle Markierten zum Ziel. Der Quelldateipfad wird vielleicht am Ziel neu erstellt, abhängig von der „Kopieren und Verschieben“ Einstellung.
  • +
  • Kopiere Markierte nach…: Fragt nach einem Ziel und kopiert alle Markierten zum Ziel. Der Quelldateipfad wird vielleicht am Ziel neu erstellt, abhängig von der „Kopieren und Verschieben“ Einstellung.
  • +
  • Entferne Markierte aus den Ergebnissen: Entfernt alle markierte Duplikate aus den Ergebnissen. Die wirklichen Dateien werden nicht angerührt und bleiben wo sie sind.
  • +
  • Entferne Ausgewählte aus den Ergebnissen: Entfernt alle ausgewählten Duplikate aus den Ergebnissen. Beachten Sie das ausgewählte Referenzen ignoriert werden, nur Duplikate können entfernt werden.
  • +
  • Mache Ausgewählte zur Referenz: Ernenne alle ausgewählten Duplikate zur Referenz. Ist ein Duplikat Teil einer Gruppe, die eine Referenzdatei aus einem Referenzordner hat (blaue Farbe), wird keine Aktion für dieses Duplikat durchgeführt. Ist mehr als ein Duplikat aus der selben Gruppe ausgewählt, wird nur das Erste jeder Gruppe befördert.
  • +
  • Füge Ausgewählte der Ignorier-Liste hinzu: Dies entfernt zuerst alle ausgewählten Duplikate aus den Ergebnissen und fügt danach das aktuelle Duplikat und die Referenz der Ignorier-Liste hinzu. Diese Treffer werden bei zukünftigen Scans nicht mehr angezeigt. Das Duplikat selbst kann wieder auftauchen, es wird dann jedoch zur einer anderen Referenz gehören. Die Ignorier-Liste kann mit dem Ignorier-Liste leeren Kommando gelöscht werden.
  • +
  • Öffne Ausgewählte mit Standardanwendung: Öffnet die Datei mit der Anwendung die mit dem Dateityp verknüpft ist.
  • +
  • Zeige Ausgewählte: Öffnet den Ordner der die ausgewählte Datei enthält.
  • +
  • Eigenen Befehl ausführen: Ruft die in den Einstellungen definierte externe Anwendung auf und nutzt die aktuelle Auswahl als Argumente für den Aufruf.
  • +
  • Ausgewählte umbenennen: Fragt nach einem neuen Namen und benennt die ausgewählte Datei um.
  • +
+
+

Zu tun

+

Add Move and iPhoto/iTunes warning

+
+
+

Zu tun

+

Add „Deletion Options“ section.

+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/de/search.html b/help/de/search.html new file mode 100644 index 00000000..5662a9eb --- /dev/null +++ b/help/de/search.html @@ -0,0 +1,76 @@ + + + + + + + + Suche — dupeGuru 4.0.3 Dokumentation + + + + + + + + + + + + + + + + + + +
+ + +

Suche

+
+ +

+ Bitte aktivieren Sie JavaScript, wenn Sie die Suchfunktion nutzen wollen. +

+
+

+ Von hier aus können Sie die Dokumentation durchsuchen. Geben Sie Ihre Suchbegriffe in das untenstehende Feld ein und klicken Sie auf "Suchen". Bitte beachten Sie, dass die Suchfunktion automatisch nach allen Worten sucht. Seiten, die nicht alle Worte enthalten, erscheinen nicht in der Ergebnisliste. +

+
+ + + +
+ +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/help/de/searchindex.js b/help/de/searchindex.js new file mode 100644 index 00000000..dac16545 --- /dev/null +++ b/help/de/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["changelog","faq","folders","index","preferences","quick_start","reprioritize","results"],envversion:53,filenames:["changelog.rst","faq.rst","folders.rst","index.rst","preferences.rst","quick_start.rst","reprioritize.rst","results.rst"],objects:{},objnames:{},objtypes:{},terms:{"32bit":0,"64bit":0,"W\u00e4ren":1,"\u00dcber":3,"\u00e4nderungszeit":7,"\u00f6ffne":7,"\u00f6ffnet":7,"\u00fcberblick":7,"\u00fcberpruf":7,"ale\u0161":0,"default":0,"export":0,"for":[0,6],"long":0,"m\u00fcssen":7,"n\u00e4chstes":1,"new":0,"short":0,"switch":0,"this":[0,1,6],"with":[0,6],Alle:[4,5],Alles:7,Also:[1,7],Anderen:2,Auf:[4,7],Damit:[5,7],Dann:1,Das:[2,4,5,7],Der:[1,2,4,7],Die:[2,7],Dies:[4,7],Diese:[4,7],Dieses:[2,7],Ein:[2,4,7],Eine:[2,7],Haben:[2,7],Hier:[1,4,7],Ihnen:7,Ihr:7,Ihre:4,Ihren:7,Ihrer:4,Ist:[2,4,7],Keine:1,Nicht:7,Nur:[1,3,4],SIe:1,Sehr:1,Sie:[1,2,3,4,5,7],Sind:7,Und:1,Was:0,Weg:[2,7],Wenn:[1,2,3,4,5,7],Wir:1,Wird:[4,7],Zum:[4,7],abgetrennt:4,abhalt:7,abhang:7,ability:0,about:0,absolut:[4,7],absteig:7,accidental:0,according:6,action:[0,4,6],activ:0,add:[0,2,6,7],added:0,adding:0,addition:6,affected:0,aft:0,again:0,aktion:[1,3,4,5],aktiv:1,aktivi:7,aktiviert:[4,7],aktuell:[3,7],alarmed:0,algorithm:0,all:[0,2,6,7],allerding:7,allow:0,allows:6,already:0,alternativ:2,analyzed:0,and:[0,2,4,6,7],anfang:5,angefasst:1,angeruhrt:7,angezeigt:[1,7],anh:0,annoyanc:0,anschalt:7,anstatt:2,anstell:[1,7],anwend:7,anwendung:[4,7],anymor:0,anyway:0,anzeig:3,anzuw:7,apertur:[0,2],app:0,application:0,applied:0,arbitrary:0,arch:0,archive2015:0,are:[0,6],aren:0,argument:[6,7],armenian:0,arrow:6,art:1,ascii:0,ask:0,attribut:0,attributeerror:0,audio:0,aufgabenbereich:4,aufgrund:1,aufruf:[4,7],auftauch:7,ausdruck:[4,7],ausfuhr:7,ausfuhrbar:4,ausgefuhrt:4,ausgeschloss:2,ausgewahlt:[1,2,5,7],ausgwahlt:4,ausnahm:7,auss:4,ausschliess:7,ausserd:7,ausserhalb:4,auswahl:[2,3,5],auswahlbox:7,auswahlt:1,auszuwahl:1,auto:0,automat:[2,7],automatic:0,automatically:6,availabl:6,avoid:0,awar:0,back:0,backend:0,bad:0,bar:[0,6],bas:0,based:0,batchmod:1,beacht:7,bearbeit:5,becam:0,bedeutet:7,bedi:2,beeinflusst:5,been:0,beendet:7,befehl:[4,7],befehlszeil:4,befind:[2,7],befindet:1,befordert:7,befordn:1,beginning:0,begutacht:5,behalt:[1,2,7],behandelt:4,behav:4,behavior:0,beid:1,beim:[4,7],being:0,beispiel:[1,4,7],beispielsweis:7,bekomm:1,below:6,bemerk:7,benennt:7,bereit:[2,4],bess:7,best:7,besteh:7,bestimm:7,bestimmt:[4,7],betracht:[5,7],betwe:0,beurteil:3,bevor:7,big:0,bigg:6,bild:4,binding:0,bit:0,bitt:4,blau:[1,7],bleib:7,blick:3,block:0,blue:0,box:[4,7],brauch:1,brazilian:0,bring:0,brok:0,bsd:0,buchstab:1,bug:0,build:0,bump:0,bundl:0,but:[0,6],button:[0,6],byt:0,cach:0,caching:0,called:0,cam:0,can:[0,6],cancel:0,cancellabl:0,cancellation:0,cancelled:0,cas:[0,6],category:6,caus:0,caused:0,causing:0,ceiled:0,cell:0,certain:0,chang:0,changed:0,changelog:3,charact:0,chines:0,choos:0,chos:0,clear:0,clev:6,click:[0,6],cmd:0,cocoa:0,collection:0,color:0,coloring:0,column:0,com:[0,6],combobox:6,comboboxmodel:0,command:[0,7],comparison:0,compatibility:0,complement:0,complet:0,configuration:0,confused:0,confusing:0,containing:0,content:0,context:0,conversion:0,converted:0,copied:0,copy:[0,4,7],cor:0,correct:0,correctly:0,corrupted:0,couldn:0,count:0,coupl:0,crash:0,created:0,creation:0,criteria:[0,6],criterion:6,csv:0,custom:0,czech:0,dadurch:7,dafur:1,danach:7,daran:7,darauf:2,dargestellt:7,darub:1,darunt:7,dat:0,datei:[2,4,5,7],dateiart:7,dateierweiter:4,datein:1,dateinam:[1,4,7],dateirecht:1,dateityp:[4,7],davon:[2,7],deaktiviert:7,debugging:0,dee:0,definiert:[1,7],delet:0,deleted:0,deletion:[0,7],delta:[0,6,7],deltawert:3,denen:[2,5],denk:1,dependenci:0,deren:7,derselb:[2,4],descriptor:0,designed:0,dess:7,destination:0,detail:[0,7],detection:0,determin:[4,6],detinov:0,dialog:[0,6],dienstprogramm:1,diff:4,directori:0,directory:0,direkt:[2,4],disabl:0,discarded:0,display:0,displayed:0,displaying:0,divers:7,documentation:0,does:[0,6],doesn:6,dokument:7,dokumentation:[3,4],don:0,doppelt:7,doubl:0,drag:[0,5,6],dramatically:0,drop:[0,5,6],dropped:0,druck:[1,5,7],due:0,dup:[0,6],dupeguru:[0,2,4,5,6,7],duplicat:[0,3],duplikat:[2,3,4,5],duplikategrupp:4,duplikatelist:7,duplikatereferenz:4,duplikatescan:7,duplikatgrupp:[1,2,3],duplikatscan:3,durchfuhr:[1,7],durchgefuhrt:7,durchsucht:2,durf:4,during:0,dutch:0,each:[0,6],ebenfall:4,echt:[1,7],eckig:7,edit:0,edition:0,efficient:0,eig:[4,7],einfach:[1,5,7],einfuhr:7,eingeb:7,eingeruckt:[5,7],eingeschloss:2,einschliess:4,einschrank:7,einstell:[1,3,7],eintrag:[2,7],elegantly:0,empty:0,enabled:0,end:[0,1,6],endgult:4,engin:[0,1],english:1,entdeck:7,entfern:[2,4,5,7],entfernt:[1,2,7],enthalt:[2,4,7],enthullt:7,entwed:[1,5],entwickelt:1,erb:2,erfahr:5,erfolg:7,ergebnis:[1,3,5],ergebnislist:[5,7],erhalt:7,eric:0,erkannt:4,erklar:[4,7],erlaubt:7,erleicht:7,ernenn:7,erneut:1,erreicht:7,error:0,erscheint:2,ersetz:7,ersetzt:[4,7],erst:[1,2,3,5,7],erste:7,erstell:[1,4],erstellt:7,ersten:1,erweiter:7,especially:0,even:0,exact:0,exampl:6,excluded:0,exclusion:0,exe:[4,7],exist:0,existi:7,existiert:[1,4],explizit:2,exporti:7,exporting:0,expression:[0,4,7],ext:4,extension:0,extern:[4,7],extr:1,fact:0,fairwar:[0,1],fall:[1,2,4],fals:0,falsch:5,falschpositiv:7,faq:1,farb:7,featur:0,feedback:0,fehlschlagt:1,feld:7,fenst:2,fertig:5,fetching:0,few:0,field:[0,7],figueiredo:0,fil:[0,4,6],filenam:[0,6],filt:[0,3,4],filteranfrag:4,filtered:0,filterempfind:[1,7],filterfunktion:[4,7],filtering:0,filterkriterium:7,find:[0,1,3,7],findet:[1,7],first:6,fix:0,fixed:0,flexibel:1,focus:0,fold:[0,6],folglich:1,followed:6,font:0,foo:6,foobar:4,form:7,format:[0,4],fortgeschritt:7,found:0,frag:3,fragt:7,frank:0,freez:0,french:0,from:0,fug:7,fugt:[1,7],fuhr:4,fuhrung:3,funktion:[1,7],fur:[1,2,3,4,5,7],fuzzy:0,gabriel:0,ganz:[1,7],geandert:7,geb:7,gefiltert:7,gefragt:2,gefund:7,geh:[1,7],gehor:7,gelang:7,geloscht:[1,2,4,7],gemacht:1,gemischt:4,genutzt:[3,7],geoffnet:7,gerad:7,german:0,gesamt:7,gesendet:4,gesetzt:7,gestartet:[2,7],gestellt:3,get:[0,6],gewahlt:4,gezeigt:7,ghosting:0,gibt:[1,5],github:0,glitch:0,going:0,gplv3:0,greatly:0,greek:0,gregor:0,gross:7,grossergleich:7,grosst:7,group:6,grouping:0,groups:0,grund:7,grupp:[1,2,7],gruppenlist:7,gui:0,gut:[3,4,7],had:0,hakch:7,halt:[3,7],handling:0,hangt:7,happening:0,hard:[0,7],hardcoded:0,hardlink:[0,7],hardlinking:0,hardness:0,has:[0,6,7],haufig:3,hav:[0,6],having:0,heisst:1,helf:1,help:0,her:0,heraus:1,herunterscroll:7,hervorgehob:7,high:6,hilfedatei:5,hilfreich:4,hinzu:[1,7],hinzufug:[2,4,7],hinzugefugt:[2,7],homepag:3,hour:0,how:[0,4],hrant:0,html:0,https:0,icon:0,idee:3,ignor:0,ignored:0,ignori:[4,7],ignoriert:7,igor:0,imm:[1,7],important:[0,6],improv:0,improved:0,improvement:0,inaccuraci:0,inconvenient:0,ind:[1,2,4,7],info:[0,4,7],information:7,inhalt:3,initial:0,inod:4,insensitiv:0,installiert:4,instead:0,interfac:0,internal:0,internationalized:0,interpreti:4,into:6,introduced:0,invocation:0,involved:0,iphoto:[0,2,7],issu:0,issued:0,italian:0,item:[0,6,7],itun:[0,2,7],jed:[2,4,5,7],jedoch:7,job:0,jumpy:0,just:0,keep:0,keeping:0,keybinding:0,kind:0,klamm:7,klein:7,kleinschreib:7,klick:[1,2,7],knopf:[2,5,7],kommando:7,kommandozeilenwerkzeug:1,kommt:7,konn:[1,2,3,4,7],konnt:1,konstrui:1,kontakti:1,kontext:7,kopi:7,kopiert:7,korean:0,koutilellis:0,kyrill:0,larg:0,lass:1,last:0,latin:0,launch:0,launching:0,leer:[4,7],leertast:[1,7],leerzeich:4,left:6,leicht:[2,3,7],length:0,les:[3,5],letzt:7,librari:2,licens:0,licensed:0,liegt:7,lik:0,limitation:0,link:7,linux:[0,4,7],lion:0,list:[0,2,6,7],littl:0,load:0,loading:0,localisation:0,localization:0,localized:0,location:0,lokalisi:7,los:[0,1],losch:[4,7],loscht:[1,7],lost:0,lot:0,low:0,mac:[0,7],mach:[1,5,7],machin:0,macht:7,macos:0,mad:0,mag:7,main:0,mak:[0,6],making:0,mal:[1,2],manch:1,manuell:[1,7],many:[0,6],mark:0,marked:0,marki:[5,7],markier:3,markiert:[1,4,5,7],markierungsfeld:5,marking:0,mass:0,match:0,mayb:0,mean:[0,6],media:0,mehr:[1,2,5,7],mehrfachauswahl:7,meist:1,memory:0,menu:[0,2,3,4,6],merg:0,messag:0,method:5,might:0,min:0,minimum:0,minor:0,mishandling:0,mistakenly:0,mitglied:1,mithilf:7,mocht:7,mod:0,modifikation:1,modifizi:1,modus:[1,7],moglich:[4,7],mor:[0,6],mostly:0,mov:[0,4,7],moved:0,moving:0,mp3:0,much:0,mulleim:[5,7],multipl:0,music:0,mydestination:4,nachd:4,nah:0,nam:[0,7],namenskonflikt:4,nasty:0,natur:2,needed:6,nehyba:0,net:0,neu:[2,3,4,7],niedrig:[1,7],niemal:[1,7],nimmt:7,non:[0,7],normal:[2,7],not:[0,2,7],nothing:0,notic:0,notiz:1,now:[0,7],numb:[0,6],numeric:0,numerical:[0,7],numm:4,nutz:[2,4,7],nutzt:7,ober:5,object:0,obsolet:0,obwohl:[3,7],occasional:0,occasionally:0,occurring:0,offn:7,ohanyan:0,ohn:[3,4,5,7],onc:0,one:[0,6],only:[0,6],open:0,opening:0,operation:[0,4],option:[0,4,5,6,7],ord:[0,6],orderabl:0,ordn:7,ordner:[2,4,5,7],ordnerauswahl:[1,3],ordnern:7,ordnerspalt:1,ordnerzustand:[3,7],outdated:1,overwrit:0,packaging:0,panel:[0,4,7],paolo:0,part:0,pass:7,passend:7,passiert:7,passt:1,path:0,pavlov:0,permission:0,permissionerror:0,petrashko:0,pfad:4,phan:0,phas:0,picked:6,picking:6,pictur:0,plac:0,platz:[4,7],platzhalt:4,play:6,pointing:6,polish:0,popping:0,popup:2,position:[0,2,6],possibility:0,post:0,pow:0,powerful:6,praktisch:7,predictably:0,pref:0,preferenc:0,present:0,pretty:0,preventing:0,previous:0,previously:6,prioritiz:[0,6],prioritization:[0,6],prioritizing:3,probl:[0,1],process:0,program:4,progress:0,propagation:0,put:0,pyqt:0,python:0,qestion:1,quelldatei:4,quelldateipfad:7,quellpfad:4,quicklook:0,quit:0,quitting:0,rahm:7,random:0,reading:0,really:0,recent:0,recht:1,recycl:0,reduc:0,ref:0,refactoring:0,referenc:[0,6],referenz:[1,2,4,7],referenzdatei:[1,5,7],referenzgruppensyst:1,referenzordn:[1,2,7],referenzordnersyst:1,referenzposition:[1,7],referenzprioritat:7,referenzzustand:1,refresh:0,refreshed:0,regexp:7,registration:0,regular:[0,4,7],reihenfolg:7,related:0,relativ:[4,7],releas:0,relevant:0,reliability:0,reload:0,reloading:0,rememb:0,remind:0,remov:0,removabl:0,removal:0,removed:0,removing:0,renam:0,renamed:0,renaming:0,repari:1,replac:0,replacing:0,report:0,reporting:0,requirement:0,reset:0,respektiv:7,responsiveness:0,restlich:[5,7],restored:0,result:[0,6],revamp:0,reveal:0,rewrit:0,richtig:1,right:[0,6],rightmost:6,roman:0,rossi:0,rounded:0,ruft:7,run:0,russian:0,sam:[0,6],sav:0,saved:0,saving:0,scan:[0,1,2,5,7],scandurchlauf:7,scann:[0,1],scanned:0,scannend:5,scanning:0,scanvorgang:5,schalt:7,schick:1,schieb:1,schliess:4,schnell:[5,7],schnellstart:3,schreib:1,screen:0,search:7,second:6,section:7,see:1,seeking:0,seh:2,sei:2,seit:1,sektion:3,selb:[1,4,7],seldom:0,select:[0,6],selected:[0,6],selecting:0,selection:0,send:[0,1],sensibl:0,sent:0,separat:0,setting:0,setz:2,shelv:0,shift:7,should:6,show:0,showing:0,sicher:[5,7],sicherheitsbedenk:1,sicherheitsgrund:1,sicherheitsmassnahm:7,sicherstell:1,sicherstellt:1,sicherzustell:1,sichtbar:7,sid:0,sieh:[1,2],sierra:0,significantly:0,similar:0,simplified:0,simply:0,sinc:0,sinnvoll:[3,7],situation:0,siz:[0,6],small:0,smartly:0,sobald:7,soft:0,softwar:0,solang:7,sollen:1,sollt:4,som:0,somefil:4,somefold:4,sometim:[0,6],sond:7,sort:0,sorti:[1,7],sortier:7,sortiert:7,sorting:[0,6],sowi:7,sowohl:1,spalt:7,spanish:0,sparkl:0,speed:0,sphinx:0,spiel:7,sprengt:7,stall:0,standard:0,standardanwend:7,standardbrows:7,standardscan:5,standardzustand:2,start:[0,4,5],started:0,starting:0,startup:0,stat:0,stattdess:7,status:0,steh:7,stellt:7,steuer:7,stichwortverzeichnis:3,sticky:0,stopped:0,stuck:0,subargument:6,subfold:[0,4],subsequent:0,such:[0,3],suchdurchlauf:5,suchfeld:7,summon:6,superdiffprog:4,support:[0,1],sur:0,surrogat:0,symbolleist:7,symlink:0,sync:0,syst:0,systematic:0,tabl:0,tast:7,tatzn:0,technical:0,teil:7,teilmeng:7,tell:0,temporar:1,temporarily:0,text:[0,7],than:0,that:[0,6],the:[0,4,6],their:0,them:0,then:[0,6],ther:[0,6],therefor:0,thes:0,thread:0,threshold:0,through:[0,6],tie:6,ties:6,tig:0,too:0,toolbar:7,trash:0,treff:[1,7],trick:6,tries:6,trying:0,tun:4,tweaked:0,two:6,typ:[0,7],typos:0,uber:[1,5,7],ubereinstimm:7,ubereinstimmt:1,ubernimmt:7,uberpruf:[4,5],ubuntu:0,ukrainian:0,umbenenn:7,umschalt:7,under:0,unecht:7,ungefiltert:7,unicod:0,unicodeencodeerror:0,universal:0,unmaintained:0,unpaid:0,unsaved:0,unt:2,unterordn:2,unterschied:4,unterseit:7,unterstutzt:7,updat:0,updated:0,upgrad:0,upgraded:0,upon:0,usag:0,use_regexp:0,used:[0,6],useful:0,user:[0,4],using:0,valu:[0,6],various:0,verand:7,verander:5,verknupft:7,verlinkt:4,verschieb:[4,5,7],verschiebt:7,verschied:7,verschob:4,versetz:1,versetzt:2,version:[0,1,3],versuch:4,vertraut:1,verweigert:1,verweis:4,verwend:[1,7],verwendet:1,verwirft:1,very:0,verzeichnis:[2,4],victor:0,viele:5,vielleicht:7,vietnames:0,vista:0,visual:0,vollstand:4,vorangegang:7,voranstellt:4,voreinstell:[5,7],vorh:2,vorhand:4,wahl:[2,5,7],wahr:7,want:0,warning:[0,7],wart:5,warum:7,wasn:0,way:0,web:0,weighting:0,welch:[1,7],well:0,wenig:7,wer:[0,6],werd:[1,2,3,4,5,7],werf:3,wert:7,when:[0,6],wher:[0,6],which:[0,6],whil:0,whol:0,wied:7,wiederhergestellt:4,wiederherzustell:4,wildcard:7,win:6,window:0,windows:[0,7],wirklich:[5,7],wirksam:7,woes:0,woll:[2,7],wond:0,word:0,work:0,workaround:1,working:0,would:0,wouldn:0,writabl:0,wrong:[0,6],wurd:[1,4,7],wurzelauswahl:4,www:0,xhtml:[0,7],yeah:0,you:[0,6],your:[0,6],yuri:0,zeich:4,zeichenkett:7,zeig:7,zeigt:7,zieh:2,ziel:[4,7],zielverzeichnis:4,zitatzeich:4,zuerst:7,zukunft:7,zuletzt:[2,7],zurechtfind:5,zuruck:7,zusammenpass:1,zusatz:7,zustand:2,zutrifft:7,zwisch:7},titles:["Changelog","H\u00e4ufig gestellte Fragen","Ordnerauswahl","dupeGuru Hilfe","Einstellungen","Schnellstart","Re-Prioritizing duplicates","Ergebnisse"],titleterms:{"\u00dcber":7,Die:1,Ich:1,Nur:7,Was:1,Wie:1,aktion:7,ala:1,all:1,and:[1,3],anzeig:7,appnam:[],auswahl:7,bedeutet:1,bess:1,bestimmt:1,beurteil:7,changelog:0,datei:1,deaktiviert:1,deltawert:7,demo:1,dupeguru:[1,3],duplicat:6,duplikat:[1,7],duplikatgrupp:7,duplikatscann:1,einschrank:1,einstell:4,ergebnis:7,filt:7,frag:1,gestellt:1,haufig:1,hilf:3,indic:3,losch:1,macht:1,marki:1,markier:7,markierungsbox:1,menu:7,mocht:1,moglich:1,mulleim:1,nachricht:1,ordner:1,ordnerauswahl:2,ordnerzustand:2,prioritizing:6,sagt:1,schnellstart:5,sicher:1,statusbar:1,tabl:3,tun:[1,2,7],verschieb:1,versucht:1,verworf:1,warum:1,what:1,wirklich:1}}) \ No newline at end of file diff --git a/help/en/.buildinfo b/help/en/.buildinfo new file mode 100644 index 00000000..a9c3179c --- /dev/null +++ b/help/en/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: a874776587ce2da814c4810262a52987 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/help/en/.doctrees/changelog.doctree b/help/en/.doctrees/changelog.doctree new file mode 100644 index 00000000..a14dfd15 Binary files /dev/null and b/help/en/.doctrees/changelog.doctree differ diff --git a/help/en/.doctrees/contribute.doctree b/help/en/.doctrees/contribute.doctree new file mode 100644 index 00000000..f6aac801 Binary files /dev/null and b/help/en/.doctrees/contribute.doctree differ diff --git a/help/en/.doctrees/developer/core/app.doctree b/help/en/.doctrees/developer/core/app.doctree new file mode 100644 index 00000000..a02b0efd Binary files /dev/null and b/help/en/.doctrees/developer/core/app.doctree differ diff --git a/help/en/.doctrees/developer/core/directories.doctree b/help/en/.doctrees/developer/core/directories.doctree new file mode 100644 index 00000000..cf4a8014 Binary files /dev/null and b/help/en/.doctrees/developer/core/directories.doctree differ diff --git a/help/en/.doctrees/developer/core/engine.doctree b/help/en/.doctrees/developer/core/engine.doctree new file mode 100644 index 00000000..ed970bc0 Binary files /dev/null and b/help/en/.doctrees/developer/core/engine.doctree differ diff --git a/help/en/.doctrees/developer/core/fs.doctree b/help/en/.doctrees/developer/core/fs.doctree new file mode 100644 index 00000000..645ca5fe Binary files /dev/null and b/help/en/.doctrees/developer/core/fs.doctree differ diff --git a/help/en/.doctrees/developer/core/gui/deletion_options.doctree b/help/en/.doctrees/developer/core/gui/deletion_options.doctree new file mode 100644 index 00000000..f772f95b Binary files /dev/null and b/help/en/.doctrees/developer/core/gui/deletion_options.doctree differ diff --git a/help/en/.doctrees/developer/core/gui/index.doctree b/help/en/.doctrees/developer/core/gui/index.doctree new file mode 100644 index 00000000..4c2c3667 Binary files /dev/null and b/help/en/.doctrees/developer/core/gui/index.doctree differ diff --git a/help/en/.doctrees/developer/core/index.doctree b/help/en/.doctrees/developer/core/index.doctree new file mode 100644 index 00000000..ea7d0248 Binary files /dev/null and b/help/en/.doctrees/developer/core/index.doctree differ diff --git a/help/en/.doctrees/developer/core/results.doctree b/help/en/.doctrees/developer/core/results.doctree new file mode 100644 index 00000000..c90598a4 Binary files /dev/null and b/help/en/.doctrees/developer/core/results.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/build.doctree b/help/en/.doctrees/developer/hscommon/build.doctree new file mode 100644 index 00000000..81752e7e Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/build.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/conflict.doctree b/help/en/.doctrees/developer/hscommon/conflict.doctree new file mode 100644 index 00000000..8e3ebcb1 Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/conflict.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/desktop.doctree b/help/en/.doctrees/developer/hscommon/desktop.doctree new file mode 100644 index 00000000..b4ee465f Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/desktop.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/gui/base.doctree b/help/en/.doctrees/developer/hscommon/gui/base.doctree new file mode 100644 index 00000000..008cf4d4 Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/gui/base.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/gui/column.doctree b/help/en/.doctrees/developer/hscommon/gui/column.doctree new file mode 100644 index 00000000..f1c3e389 Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/gui/column.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/gui/progress_window.doctree b/help/en/.doctrees/developer/hscommon/gui/progress_window.doctree new file mode 100644 index 00000000..898a7f40 Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/gui/progress_window.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/gui/selectable_list.doctree b/help/en/.doctrees/developer/hscommon/gui/selectable_list.doctree new file mode 100644 index 00000000..a556301b Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/gui/selectable_list.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/gui/table.doctree b/help/en/.doctrees/developer/hscommon/gui/table.doctree new file mode 100644 index 00000000..7b084f97 Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/gui/table.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/gui/text_field.doctree b/help/en/.doctrees/developer/hscommon/gui/text_field.doctree new file mode 100644 index 00000000..597a48fa Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/gui/text_field.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/gui/tree.doctree b/help/en/.doctrees/developer/hscommon/gui/tree.doctree new file mode 100644 index 00000000..5b58da31 Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/gui/tree.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/index.doctree b/help/en/.doctrees/developer/hscommon/index.doctree new file mode 100644 index 00000000..f6f45076 Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/index.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/jobprogress/job.doctree b/help/en/.doctrees/developer/hscommon/jobprogress/job.doctree new file mode 100644 index 00000000..9acc9284 Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/jobprogress/job.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/jobprogress/performer.doctree b/help/en/.doctrees/developer/hscommon/jobprogress/performer.doctree new file mode 100644 index 00000000..a8ff7fcb Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/jobprogress/performer.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/jobprogress/qt.doctree b/help/en/.doctrees/developer/hscommon/jobprogress/qt.doctree new file mode 100644 index 00000000..c8790603 Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/jobprogress/qt.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/notify.doctree b/help/en/.doctrees/developer/hscommon/notify.doctree new file mode 100644 index 00000000..c40df533 Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/notify.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/path.doctree b/help/en/.doctrees/developer/hscommon/path.doctree new file mode 100644 index 00000000..fbfdc28f Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/path.doctree differ diff --git a/help/en/.doctrees/developer/hscommon/util.doctree b/help/en/.doctrees/developer/hscommon/util.doctree new file mode 100644 index 00000000..765fd2d6 Binary files /dev/null and b/help/en/.doctrees/developer/hscommon/util.doctree differ diff --git a/help/en/.doctrees/developer/index.doctree b/help/en/.doctrees/developer/index.doctree new file mode 100644 index 00000000..1b977201 Binary files /dev/null and b/help/en/.doctrees/developer/index.doctree differ diff --git a/help/en/.doctrees/environment.pickle b/help/en/.doctrees/environment.pickle new file mode 100644 index 00000000..9888ac58 Binary files /dev/null and b/help/en/.doctrees/environment.pickle differ diff --git a/help/en/.doctrees/faq.doctree b/help/en/.doctrees/faq.doctree new file mode 100644 index 00000000..36a598be Binary files /dev/null and b/help/en/.doctrees/faq.doctree differ diff --git a/help/en/.doctrees/folders.doctree b/help/en/.doctrees/folders.doctree new file mode 100644 index 00000000..f861d5ec Binary files /dev/null and b/help/en/.doctrees/folders.doctree differ diff --git a/help/en/.doctrees/index.doctree b/help/en/.doctrees/index.doctree new file mode 100644 index 00000000..41e1a530 Binary files /dev/null and b/help/en/.doctrees/index.doctree differ diff --git a/help/en/.doctrees/preferences.doctree b/help/en/.doctrees/preferences.doctree new file mode 100644 index 00000000..58f2eee4 Binary files /dev/null and b/help/en/.doctrees/preferences.doctree differ diff --git a/help/en/.doctrees/quick_start.doctree b/help/en/.doctrees/quick_start.doctree new file mode 100644 index 00000000..7b5356e9 Binary files /dev/null and b/help/en/.doctrees/quick_start.doctree differ diff --git a/help/en/.doctrees/reprioritize.doctree b/help/en/.doctrees/reprioritize.doctree new file mode 100644 index 00000000..57b39dd0 Binary files /dev/null and b/help/en/.doctrees/reprioritize.doctree differ diff --git a/help/en/.doctrees/results.doctree b/help/en/.doctrees/results.doctree new file mode 100644 index 00000000..452ed306 Binary files /dev/null and b/help/en/.doctrees/results.doctree differ diff --git a/help/en/.doctrees/scan.doctree b/help/en/.doctrees/scan.doctree new file mode 100644 index 00000000..4275566c Binary files /dev/null and b/help/en/.doctrees/scan.doctree differ diff --git a/help/en/_sources/changelog.rst.txt b/help/en/_sources/changelog.rst.txt new file mode 100644 index 00000000..b1fc6f65 --- /dev/null +++ b/help/en/_sources/changelog.rst.txt @@ -0,0 +1,705 @@ +:tocdepth: 1 + +Changelog +========= + +**About the word "crash":** When reading this changelog, you might be alarmed at the number of fixes +for "crashes". Be aware that when the word "crash" is used here, it refers to "soft crashes" which +don't cause the application to quit. You simply get an error window that asks you if you want to +send the crash report to Hardcoded Software. Crashes that cause the application to quit are called +"hard crashes" in this changelog. + + +4.0.3 (2016-11-24) +---------------------- + +* Add new picture cache backend: shelve +* Make shelve picture cache backend the active one on MacOS to fix `#394 `__ more + elegantly. [cocoa] +* Remove Sparkle (auto-updates) due to technical limitations. [cocoa] + + +4.0.2 (2016-10-09) +---------------------- + +* Fix systematic crash in Picture Mode under MacOS Sierra. (`#394 `__) +* No change for Linux. Just keeping version in sync. + + +4.0.1 (2016-08-24) +---------------------- + +* Add Greek localization, by Gabriel Koutilellis. (`#382 `__) +* Fix localization base path. [qt] (`#378 `__) +* Fix broken load results dialog. [qt] +* Fix crash on load results. [cocoa] (`#380 `__) +* Save preferences more predictably. [qt] (`#379 `__) +* Fix picture mode's fuzzy block scanner threshold. (`#387 `__) + + +4.0.0 (2016-07-01) +---------------------- + +* Merge Standard, Music and Picture editions in the same application! +* Improve documentation. (`#294 `__) +* Add Polish, Korean, Spanish and Dutch localizations. +* qt: Fix wrong use_regexp option propagation to core. (`#295 `__) +* qt: Fix progress window mistakenly showing up on startup. (`#357 `__) +* Bump Python requirement to v3.4. +* Bump OS X requirement to 10.8 +* Drop Windows support, maybe temporarily. + `Details `__-11-01>`_ +* cocoa: Drop iPhoto, Aperture and iTunes support. Was unmaintained and obsolete. +* Drop "Audio Contents" scan type. Was confusing and seldom useful. +* Change license to GPLv3 + + +3.9.1 (2014-10-17) +---------------------- + +* Fixed ``AttributeError: 'ComboboxModel' object has no attribute 'reset'``. [Linux, Windows] (`#254 `__) +* Fixed ``PermissionError`` on saving results. (`#266 `__) +* Fixed a build problem introduced by Sphinx 1.2.3. +* Updated German localisation, by Frank Weber. + + +3.9.0 (2014-04-19) +---------------------- + +* This is mostly a dependencies upgrade. +* Upgraded to Python 3.3. +* Upgraded to Qt 5. +* Minimum Windows version is now Windows 7 64bit. +* Minimum Ubuntu version is now 14.04. +* Minimum OS X version is now 10.7 (Lion). +* ... But with a couple of little improvements. +* Improved documentation. +* Overwrite subfolders' state when setting states in folder dialog (`#248 `__) +* The error report dialog now brings the user to Github issues. + + +3.8.0 (2013-12-07) +---------------------- + +* Disable symlink/hardlink deletion option when not relevant. (`#247 `__) +* Make Cmd+A select all folders in the Folder Selection dialog. [Mac] (`#228 `__) +* Make non-numeric delta comparison case insensitive. (`#239 `__) +* Fix surrogate-related UnicodeEncodeError on CSV export. (`#210 `__) +* Fixed crash on Dupe Count sorting with Delta + Dupes Only. (`#238 `__) +* Improved documentation. +* Important internal refactorings. +* Dropped Ubuntu 12.04 and 12.10 support. +* Removed the fairware dialog (`More Info `__). + + +3.7.1 (2013-08-19) +---------------------- + +* Fixed folder scan type, which was broken in v3.7.0. + + +3.7.0 (2013-08-17) +---------------------- + +* Improved delta values to support non-numerical values. (`#213 `__) +* Improved the Re-Prioritize dialog's UI. (`#224 `__) +* Added hardlink/symlink support on Windows Vista+. (`#220 `__) +* Dropped 32bit support on Mac OS X. +* Added Vietnamese localization by Phan Anh. + + +3.6.1 (2013-04-28) +---------------------- + +* Improved "Make Selection Reference" to make it clearer. (`#222 `__) +* Improved "Open Selected" to allow opening more than one file at once. (`#142 `__) +* Fixed a few typos here and there. (`#216 `__ `#225 `__) +* Tweaked the fairware dialog (`More Info `__). +* Added Arch Linux packaging +* Added a 64-bit build for Windows. +* Improved Russian localization by Kyrill Detinov. +* Improved Brazilian localization by Victor Figueiredo. + + +3.6.0 (2012-08-08) +---------------------- + +* Added "Export to CSV". (`#189 `__) +* Added "Replace with symlinks" to complement "Replace with hardlinks". [Mac, Linux] (`#194 `__) +* dupeGuru now tells how many duplicates were affected after each re-prioritization operation. (`#204 `__) +* Added Longest/Shortest filename criteria in the re-prioritize dialog. (`#198 `__) +* Fixed result table cells which mistakenly became writable in v3.5.0. [Mac] (`#203 `__) +* Fixed "Rename Selected" which was broken since v3.5.0. [Mac] (`#202 `__) +* Fixed a bug where "Reset to Defaults" in the Columns menu wouldn't refresh menu items' marked state. +* Added Brazilian localization by Victor Figueiredo. + + +3.5.0 (2012-06-01) +---------------------- + +* Added a Deletion Options panel. +* Greatly improved memory usage for big scans. +* Added a keybinding for the filter field. (`#182 `__) [Mac] +* Upgraded minimum requirements for Ubuntu to 12.04. + + +3.4.1 (2012-04-14) +---------------------- + +* Fixed the "Folders" scan type. [Mac] +* Fixed localization issues. [Windows, Linux] + + +3.4.0 (2012-03-29) +---------------------- + +* Improved results window UI. [Windows, Linux] +* Added a dialog to edit the Ignore List. +* Added the ability to sort results by "marked" status. +* Fixed "Open with default application". (`#190 `__) +* Fixed a bug where there would be a false reporting of discarded matches. (`#195 `__) +* Fixed various localization glitches. +* Fixed hard crashes on crash reporting. (`#196 `__) +* Fixed bug where the details panel would show up at inconvenient places in the screen. [Windows, Linux] + + +3.3.3 (2012-02-01) +---------------------- + +* Fixed crash on adding some folders. [Mac OS X] +* Added Ukrainian localization by Yuri Petrashko. + + +3.3.2 (2012-01-16) +---------------------- + +* Fixed random hard crashes (yeah, again). [Mac OS X] +* Fixed crash on Export to HTML. [Windows, Linux] +* Added Armenian localization by Hrant Ohanyan. +* Added Russian localization by Igor Pavlov. + + +3.3.1 (2011-12-02) +---------------------- + +* Fixed a couple of nasty crashes. + + +3.3.0 (2011-11-30) +---------------------- + +* Added multiple-selection in folder selection dialog for a more efficient folder removal. (`#179 `__) +* Fixed a crash in the prioritize dialog. (`#178 `__) +* Fixed a bug where mass marking with a filter would mark more than filtered duplicates. (`#181 `__) +* Fixed random hard crashes. [Mac OS X] (`#183 `__ `#184 `__) +* Added Czech localization by Aleš Nehyba. +* Added Italian localization by Paolo Rossi. + + +3.2.1 (2011-10-02) +---------------------- + +* Fixed a couple of broken action bindings from v3.2.0. + + +3.2.0 (2011-09-27) +---------------------- + +* Added duplicate re-prioritization dialog. (`#138 `__) +* Added font size preference for duplicate table. (`#82 `__) +* Added Quicklook support. [Mac OS X] (`#21 `__) +* Improved behavior of Mark Selected. (`#139 `__) +* Improved filename sorting. (`#169 `__) +* Added Chinese (Simplified) localization by Eric Dee. +* Tweaked the fairware system. +* Upgraded minimum requirements to OS X 10.6 and Ubuntu 11.04. + + +3.1.2 (2011-08-25) +---------------------- + +* Fixed a bug preventing the Folders scan from working. (`#172 `__) + + +3.1.1 (2011-08-24) +---------------------- + +* Added German localization by Gregor Tätzner. +* Improved OS X Lion compatibility. [Mac OS X] +* Made the file collection phase cancellable. (`#168 `__) +* Fixed glitch in folder window upon selecting a folder state. [Windows, Linux] (`#165 `__) +* Fixed a text coloring glitch in the results. (`#156 `__) +* Fixed glitch in the sorting feature of the Folder column. (`#161 `__) +* Make sure that saved results have the ".dupeguru" extension. [Linux] (`#157 `__) + + +3.1.0 (2011-04-16) +---------------------- + +* Added the "Folders" scan type. (`#89 `__) +* Fixed a couple of crashes. (`#140 `__ `#149 `__) + + +3.0.2 (2011-03-16) +---------------------- + +* Fixed crash after removing marked dupes. (`#140 `__) +* Fixed crash on error handling. [Windows] (`#144 `__) +* Fixed crash on copy/move. [Windows] (`#148 `__) +* Fixed crash when launching dupeGuru from a very long folder name. [Mac OS X] (`#119 `__) +* Fixed a refresh bug in directory panel. (`#153 `__) +* Improved reliability of the "Send to Trash" operation. [Linux] +* Tweaked Fairware reminders. + + +3.0.1 (2011-01-27) +---------------------- + +* Restored the context menu which had been broken in 3.0.0. [Mac OS X] (`#133 `__) +* Fixed a bug where an "unsaved results" warning would be issued on quit even with empty results. (`#134 `__) +* Removed focus from the cancel button in the progress dialog to avoid accidental cancellations. [Mac OS X] (`#135 `__) +* Folders added through drag and drop are added to the recent folders list. (`#136 `__) +* Added a debugging mode. (`#132 `__) +* Fixed french localization glitches. + + +3.0.0 (2011-01-24) +---------------------- + +* Re-designed the UI. (`#129 `__) +* Internationalized dupeGuru and localized it to french. (`#32 `__) +* Changed the format of the help file. (`#130 `__) + + +2.12.3 (2011-01-01) +---------------------- + +* Fixed bug causing results to be corrupted after a scan cancellation. (`#120 `__) +* Fixed crash when fetching Fairware unpaid hours. (`#121 `__) +* Fixed crash when replacing files with hardlinks. (`#122 `__) + + +2.12.2 (2010-10-05) +---------------------- + +* Fixed delta column colors which were broken since 2.12.0. +* Fixed column sorting crash. (`#108 `__) +* Fixed occasional crash during scan. (`#106 `__) + + +2.12.1 (2010-09-30) +---------------------- + +* Re-licensed dupeGuru to BSD and made it `Fairware `__. + + +2.12.0 (2010-09-26) +---------------------- + +* Improved UI with a little revamp. +* Added the possibility to place hardlinks to references after having deleted duplicates. [Mac OS X, Linux] (`#91 `__) +* Added an option to ignore duplicates hardlinking to the same file. [Mac OS X, Linux] (`#92 `__) +* Added multiple selection in the "Add Directory" dialog. [Mac OS X] (`#105 `__) +* Fixed a bug preventing drag & drop from working in the Directories panel. [Windows, Linux] + + +2.11.1 (2010-08-26) +---------------------- + +* Fixed HTML exporting which was broken in 2.11.0. + + +2.11.0 (2010-08-18) +---------------------- + +* Added the ability to save results (and reload them) at arbitrary locations. +* Improved the way reference files in dupe groups are chosen. (`#15 `__) +* Remember size/position of all windows between launches. (`#102 `__) +* Fixed a bug sometimes preventing dupeGuru from reloading previous results. +* Fixed a bug sometimes causing the progress dialog to be stuck there. [Mac OS X] (`#103 `__) +* Removed the Creation Date column, which wasn't displaying the correct value anyway. (`#101 `__) + + +2.10.1 (2010-07-15) +---------------------- + +* Fixed a couple of crashes. (`#95 `__, `#97 `__, `#100 `__) + + +2.10.0 (2010-04-13) +---------------------- + +* Improved error messages when files can't be sent to trash, moved or copied. +* Added a custom command invocation action. (`#12 `__) +* Filters are now applied on whole paths. (`#4 `__) + + +2.9.2 (2010-02-10) +---------------------- + +* dupeGuru is now 64-bit on Mac OS X! +* Fixed a crash upon quitting when support folder is not present. (`#83 `__) +* Fixed a crash during sorting. (`#85 `__) +* Fixed selection glitches, especially while renaming. (`#93 `__) + + +2.9.1 (2010-01-13) +---------------------- + +* Improved memory usage for Contents scans. (`#75 `__) +* Improved scanning speed when ref directories are involved. (`#77 `__) +* Show a message dialog at the end of the scan if no duplicates are found. (`#81 `__) +* Fixed a bug sometimes causing the small files threshold pref to be ignored. [Mac OS X] (`#75 `__) + + +2.9.0 (2009-11-03) +---------------------- + +* Significantly improved speed and memory usage of big contents-based scans. +* Added drag & drop support in the Directories panel. (`#9 `__) +* Fixed a bug causing dupeGuru to be confused if a scanned file was moved during the scan. (`#72 `__) +* Dropped support for Mac OS X 10.4 (Tiger) + + +2.8.2 (2009-10-14) +---------------------- + +* Improved directory selection in the Directories panel (Windows). (`#56 `__) +* Fixed a bug preventing dupeGuru from starting on certain machines (Windows). (`#68 `__) +* Fixed a crash during very big scans. (`#70 `__) + + +2.8.1 (2009-10-02) +---------------------- + +* Fixed crash with filtering when regular expressions were enabled. (`#60 `__) +* Fixed crash when setting directories' state. (Mac OS X) (`#66 `__) +* Fixed crash with Make Reference when certain filters are applied. (Mac OS X) (`#55 `__) +* Improved error handling during delete/move/copy actions. (`#62 `__ `#65 `__) + + +2.8.0 (2009-09-07) +---------------------- + +* Added support for all kinds of bundle (not just applications) (Mac OS X) (`#11 `__) +* Re-introduced the Export to XHTML feature to Windows. (`#14 `__) +* Improved Export to XHTML speed. (`#14 `__) +* Improved Contents scanning speed for large files. (`#33 `__) +* Improved the grouping algorithm to reduce the number of discarded files in non-exact scans. (`#51 `__) +* Stopped showing the same file on the 2 sides of the details panel when a ref file is selected. (`#50 `__) +* Fixed crashes in the Directories panel. (`#46 `__) + + +2.7.3 (2009-06-20) +---------------------- + +* Fixed bugs with selection being jumpy during "Make Reference" actions and Power Marker + switches. (`#3 `__) +* Fixed crash happening when a file with non-roman characters couldn't be analyzed. (`#30 `__) +* Fixed crash sometimes happening during the file collection phase in scanning. (`#38 `__) +* Restored double-click and right-click behavior lost in the PyQt move (Windows). (`#34 `__ `#35 `__) + + +2.7.2 (2009-06-10) +---------------------- + +* Fixed an occasional crash on Copy/Move operations. (`#16 `__) +* Added automatic exclusion for sensible folders (like system folders). (`#20 `__) +* Fixed an occasional crash when application files were part of the results (Mac OS X). (`#25 `__) + + +2.7.1 (2009-05-29) +---------------------- + +* Fixed a bug causing crashes when having application files in the results. +* Fixed a bug causing a GUI freeze at the beginning of a scan with a lot of files. +* Fixed a bug that sometimes caused a crash when an action was cancelled, and then started again. + + +2.7.0 (2009-05-25) +---------------------- + +* Converted the Windows GUI to Qt. +* Improved the reliability of the scanning process. + + +2.6.1 (2009-03-27) +---------------------- + +* **Fixed** an occasional crash caused by permission issues. +* **Fixed** a bug where the "X discarded" notice would show a too large number of discarded + duplicates. + + +2.6.0 (2008-09-10) +---------------------- + +* **Added** a small file threshold preference. +* **Added** a notice in the status bar when matches were discarded during the scan. +* **Improved** duplicate prioritization (smartly chooses which file you will keep). +* **Improved** scan progress feedback. +* **Improved** responsiveness of the user interface for certain actions. + + +2.5.4 (2008-08-10) +---------------------- + +* **Improved** the speed of results loading and saving. +* **Fixed** a crash sometimes occurring during duplicate deletion. + + +2.5.3 (2008-07-08) +---------------------- + +* **Improved** unicode handling for filenames. dupeGuru will now find a lot more duplicates if your files have non-ascii characters in it. +* **Fixed** "Clear Ignore List" crash in Windows. + + +2.5.2 (2008-01-10) +---------------------- + +* **Improved** the handling of low memory situations. +* **Improved** the directory panel. The "Remove" button changes to "Put Back" when an excluded directory is selected. +* **Improved** scan, delete and move speed in situations where there were a lot of duplicates. +* **Fixed** occasional crashes when moving bundles (such as .app files). +* **Fixed** occasional crashes when moving a lot of files at once. + + +2.5.1 (2007-11-22) +---------------------- + +* **Added** the "Remove empty folders" option. +* **Fixed** results load/save issues. +* **Fixed** occasional status bar inaccuracies when the results are filtered. + + +2.5.0 (2007-09-15) +---------------------- + +* **Added** post scan filtering. +* **Fixed** issues with the rename feature under Windows +* **Fixed** some user interface annoyances under Windows + + +2.4.8 (2007-04-14) +---------------------- + +* **Improved** UI responsiveness (using threads) under Mac OS X. +* **Improved** result load/save speed and memory usage. + + +2.4.7 (2007-03-10) +---------------------- + +* **Fixed** a "bad file descriptor" error occasionally popping up. +* **Fixed** a bug with non-latin directory names. + + +2.4.6 (2007-02-10) +---------------------- + +* **Added** Re-orderable columns. In fact, I re-added the feature which was lost in the C# conversion in 2.4.0 (Windows). +* **Changed** the behavior of the scanning engine when setting the hardness to 100. It will now only match files that have their words in the same order. +* **Fixed** a bug with all the Delete/Move/Copy actions with certain kinds of files. + + +2.4.5 (2007-01-11) +---------------------- + +* **Fixed** a bug with the Move action. + + +2.4.4 (2007-01-07) +---------------------- + +* **Fixed** a "ghosting" bug. Dupes deleted by dupeGuru would sometimes come back in subsequent scans (Windows). +* **Fixed** bugs sometimes making dupeGuru crash when marking a dupe (Windows). +* **Fixed** some minor visual glitches (Windows). + + +2.4.3 (2006-12-08) +---------------------- + +* **Fixed** a mishandling of ".app" files (OS X). +* **Fixed** a bug preventing files from "reference" directories to be displayed in blue in the results (Windows). +* **Fixed** a bug preventing some files to be sent to the recycle bin (Windows). +* **Fixed** a bug in the packaging preventing certain Windows configurations to start dupeGuru at all. + + +2.4.2 (2006-11-18) +---------------------- + +* **Fixed** a bug with directory states. + + +2.4.1 (2006-11-15) +---------------------- + +* **Fixed** a bug causing the ignore list not to be saved. +* **Fixed** a bug sometimes making delete and move operations stall. + + +2.4.0 (2006-11-10) +---------------------- + +* **Changed** the Windows interface. It is now .NET based. +* **Added** an auto-update feature to the windows version. +* **Changed** the way power marking works. It is now a mode instead of a separate window. +* **Changed** the "Size (MB)" column for a "Size (KB)" column. The values are now "ceiled" instead of rounded. Therefore, a size "0" is now really 0 bytes, not just a value too small to be rounded up. It is also the case for delta values. +* **Removed** the min word length/count options. These came from Mp3 Filter, and just aren't used anymore. Word weighting does pretty much the same job. + + +2.3.4 (2006-11-07) +---------------------- + +* **Improved** speed and memory usage of the scanning engine, again. Does it mean there was a lot of improvements to be made? Nah... + + +2.3.3 (2006-11-02) +---------------------- + +* **Improved** speed and memory usage of the scanning engine, especially when the scan results in a lot of duplicates. +* Now I wonder if Sparkle is going to work well... + + +2.3.2 (2006-10-16) +---------------------- + +* **Added** an auto-update feature in the Mac OS X version (with Sparkle). +* **Fixed** a bug preventing some duplicate reports to be created correctly under Windows. + + +2.3.1 (2006-10-02) +---------------------- + +* **Fixed** a bug preventing some duplicates to be found, especially when scanning lots of files. + + +2.3.0 (2006-09-22) +---------------------- + +* **Added** XHTML export feature. + + +2.2.10 (2006-08-31) +---------------------- + +* **Added** sticky columns. +* **Fixed** an issue with file caching between scans. +* **Fixed** an issue preventing some duplicates from being deleted/moved/copied. + + +2.2.9 (2006-08-27) +---------------------- + +* **Fixed** an issue with ignore list and unicode. +* **Fixed** an issue with file attribute fetching sometimes causing dupeGuru to crash. +* **Fixed** an issue in the directories panel under Windows. + + +2.2.8 (2006-08-17) +---------------------- + +* **Fixed** an issue in the duplicate seeking engine preventing some duplicates to be found. + + +2.2.7 (2006-08-12) +---------------------- + +* **Improved** unicode support. +* **Improved** the "Reveal in Finder" ("Open Containing Folder" in Windows) feature so it selects the file in the folder it opens. + + +2.2.6 (2006-08-07) +---------------------- + +* **Improved** the ignore list system. +* dupeGuru is now a Universal application on Mac OS X. + + +2.2.5 (2006-07-26) +---------------------- + +* **Improved** application (.app) dupe detection on Mac OS X. +* **Fixed** an issue that occasionally made dupeGuru crash on startup. + + +2.2.4 (2006-06-27) +---------------------- + +* **Fixed** an issue with Move and Copy features. + + +2.2.3 (2006-06-15) +---------------------- + +* **Improved** duplicate scanning speed. +* **Added** a warning that a file couldn't be renamed if a file with the same name already exists. + + +2.2.2 (2006-06-07) +---------------------- + +* **Added** "Rename Selected" feature. +* **Fixed** some minor issues with "Reload Last Results" feature. +* **Fixed** ignore list issues. + + +2.2.1 (2006-05-22) +---------------------- + +* **Fixed** occasional progress bar woes under Windows. +* **Fixed** a bug in the registration system under Windows. +* Nothing has been changed in the Mac OS X version, but I want to keep version in sync. + + +2.2.0 (2006-05-10) +---------------------- + +* **Added** destination path re-creation options. +* **Added** an ignore list. +* **Changed** the main icon. +* **Improved** dramatically the delta values feature. + + +2.1.2 (2006-04-18) +---------------------- + +* **Added** the "Match similar words" option. +* **Fixed** Power marking issues under Mac. + + +2.1.1 (2006-04-14) +---------------------- + +* **Added** the "Display delta values" option. +* **Improved** Power marking sorting speed under Mac. +* **Fixed** Power marking sorting issues. + + +2.1.0 (2006-04-03) +---------------------- + +* **Added** the Power Marker feature. +* **Fixed** a column sorting bug. The results would sometimes lose their sort order. +* **Fixed** a bug with the Make Reference feature. The results sometimes wasn't correctly refreshed after the reference switch. + + +2.0.1 (2006-03-23) +---------------------- + +* **Fixed** an issue occasionally occurring when trying to reload results from removable media that is no longer present. + + +2.0.0 (2006-03-17) +---------------------- + +* Complete rewrite. +* Now runs on Mac OS X. + + +1.0.0 (2004-09-24) +---------------------- + +* Initial release. + diff --git a/help/en/_sources/contribute.rst.txt b/help/en/_sources/contribute.rst.txt new file mode 100644 index 00000000..f0e46c70 --- /dev/null +++ b/help/en/_sources/contribute.rst.txt @@ -0,0 +1,91 @@ +Contribute to dupeGuru +====================== + +dupeGuru was started as shareware (thus proprietary) so it doesn't have a legacy of +community-building. It's `been open source`_ for a while now and, although I've ("I" being Virgil +Dupras, author of the software) always wanted to have people other than me working on dupeGuru, I've +failed at attracting them. + +Since the end of 2013, I've been putting a lot of efforts into dupeGuru's +:doc:`developer documentation ` and I'm more serious about my commitment to create +a community around this project. + +So, whatever your skills, if you're interested in contributing to dupeGuru, please do so. Normally, +this documentation should be enough to get you started, but if it isn't, then **please**, +`let me know`_ because it's a problem that I'm committed to fix. If there's any situation where you'd +wish to contribute but some doubt you're having prevent you from going forward, please contact me. +I'd much prefer to spend the time figuring out with you whether (and how) you can contribute than +taking the chance of missing that opportunity. + +Development process +------------------- + +* `Source code repository`_ +* `Issue Tracker`_ +* `Issue labels meaning`_ + +dupeGuru's source code is on Github and thus managed in a Git repository. At all times, you should +be able to build from source a fresh checkout of the ``master`` branch using instructions from the +``README.md`` file at the root of this project. If you can't, it's a bug. Please report it. + +``master`` is the main development branch, and thus represents what going to be included in the +next feature release. When needed, we create maintenance branches for bugfixes of the current +feature release. + +When implementing a big feature, it's possible that it gets its own branch until +it's stable enough to merge into ``master``. + +Every release is tagged, the tag name containing the edition (for old versions) and its version. +For example, release 6.6.0 of dupeGuru ME is tagged ``me6.6.0``. Newer releases are tagged only +with the version number (because editions don't exist anymore), for example ``4.0.0``. + +Once you're past building the software, the :doc:`developer documentation ` should +be enough to get you started with actual development. Then again, proper documentation is a very +difficult task and, in the case of dupeGuru, this documentation was practically nonexistent until +late in the project, so it's still lacking. + +However, I'm committed to fix this situation, so if you're in a situation where you lack proper +documentation to figure something out about this code, please contact me. + +Tasks for non-developers +------------------------ + +**Create and comment issues**. The single most useful way for a user who is not a developer to +contribute to a software project is by thoroughly documenting a bug or a feature request. Most of +the time, what we get as developers are emails like "the app crashes" and we spend a lot of time +trying to figure out the cause of that bug. By properly describing the nature and context of a crash +(we learn to do that with experience as a user who reports bugs), you help developers so immensely, +you have no idea. + +It's the same thing with feature requests. Description of a feature request, when thoughts have +already been given to how such a feature would fit in the current design, are precious to developers +and help them figure out a clear roadmap for the project. + +So, even if you're not a developer, you can always open a Github account and create/comment issues. +Your contribution will be much appreciated. + +**Documentation**. This is a bit trickier because dupeGuru's documentation is written with a rather +complex markup language, `Sphinx`_ (based on `reST`_). To properly work within the documentation, +you have to know that language. I don't think that learning this language is outside the realm of +possibility for a non-developer, but it might be a daunting task. + +That being said, if it's a minor modification to the documentation, nothing stops you from opening +an issue (there's a label for documentation issues, so this kind of issue is relevant to the +tracker) describing the change you propose to make and I'll be happy to make the change myself (if +relevant, of course). + +Even if it's a bigger contribution to the documentation you want to make, I probably wouldn't mind +doing the formatting myself. But in that case, it's better to contact me first to make sure that we +agree on what should be added to the documentation. + +**Translation**. Creating or improving an existing translation is a very good way to contribute to +dupeGuru. For more information about how to do that, you can refer to the `translator guide`_. + +.. _been open source: https://www.hardcoded.net/articles/free-as-in-speech-fair-as-in-trade +.. _let me know: mailto:hsoft@hardcoded.net +.. _Source code repository: https://github.com/hsoft/dupeguru +.. _Issue Tracker: https://github.com/hsoft/dupeguru/issues +.. _Issue labels meaning: https://github.com/hsoft/dupeguru/wiki/issue-labels +.. _Sphinx: http://sphinx-doc.org/ +.. _reST: http://en.wikipedia.org/wiki/ReStructuredText +.. _translator guide: https://github.com/hsoft/dupeguru/wiki/Translator-Guide diff --git a/help/en/_sources/developer/core/app.rst.txt b/help/en/_sources/developer/core/app.rst.txt new file mode 100644 index 00000000..b183bcca --- /dev/null +++ b/help/en/_sources/developer/core/app.rst.txt @@ -0,0 +1,5 @@ +core.app +======== + +.. automodule:: core.app + :members: diff --git a/help/en/_sources/developer/core/directories.rst.txt b/help/en/_sources/developer/core/directories.rst.txt new file mode 100644 index 00000000..0854f091 --- /dev/null +++ b/help/en/_sources/developer/core/directories.rst.txt @@ -0,0 +1,5 @@ +core.directories +================ + +.. automodule:: core.directories + :members: diff --git a/help/en/_sources/developer/core/engine.rst.txt b/help/en/_sources/developer/core/engine.rst.txt new file mode 100644 index 00000000..3258c776 --- /dev/null +++ b/help/en/_sources/developer/core/engine.rst.txt @@ -0,0 +1,36 @@ +core.engine +=========== + +.. automodule:: core.engine + + .. autoclass:: Match + + .. autoclass:: Group + :members: + + .. autofunction:: build_word_dict + .. autofunction:: compare + .. autofunction:: compare_fields + .. autofunction:: getmatches + .. autofunction:: getmatches_by_contents + .. autofunction:: get_groups + .. autofunction:: merge_similar_words + .. autofunction:: reduce_common_words + +.. _fields: + +Fields +------ + +Fields are groups of words which each represent a significant part of the whole name. This concept +is sifnificant in music file names, where we often have names like "My Artist - a very long title +with many many words". + +This title has 10 words. If you run as scan with a bit of tolerance, let's say 90%, you'll be able +to find a dupe that has only one "many" in the song title. However, you would also get false +duplicates from a title like "My Giraffe - a very long title with many many words", which is of +course a very different song and it doesn't make sense to match them. + +When matching by fields, each field (separated by "-") is considered as a separate string to match +independently. After all fields are matched, the lowest result is kept. In the "Giraffe" example we +gave, the result would be 50% instead of 90% in normal mode. diff --git a/help/en/_sources/developer/core/fs.rst.txt b/help/en/_sources/developer/core/fs.rst.txt new file mode 100644 index 00000000..c6275428 --- /dev/null +++ b/help/en/_sources/developer/core/fs.rst.txt @@ -0,0 +1,5 @@ +core.fs +======= + +.. automodule:: core.fs + :members: diff --git a/help/en/_sources/developer/core/gui/deletion_options.rst.txt b/help/en/_sources/developer/core/gui/deletion_options.rst.txt new file mode 100644 index 00000000..2fbc7f8a --- /dev/null +++ b/help/en/_sources/developer/core/gui/deletion_options.rst.txt @@ -0,0 +1,5 @@ +core.gui.deletion_options +========================= + +.. automodule:: core.gui.deletion_options + :members: diff --git a/help/en/_sources/developer/core/gui/index.rst.txt b/help/en/_sources/developer/core/gui/index.rst.txt new file mode 100644 index 00000000..0298f4b9 --- /dev/null +++ b/help/en/_sources/developer/core/gui/index.rst.txt @@ -0,0 +1,10 @@ +core.gui +======== + +.. automodule:: core.gui + :members: + +.. toctree:: + :maxdepth: 2 + + deletion_options diff --git a/help/en/_sources/developer/core/index.rst.txt b/help/en/_sources/developer/core/index.rst.txt new file mode 100644 index 00000000..8c88e7e1 --- /dev/null +++ b/help/en/_sources/developer/core/index.rst.txt @@ -0,0 +1,12 @@ +core +==== + +.. toctree:: + :maxdepth: 2 + + app + fs + engine + directories + results + gui/index diff --git a/help/en/_sources/developer/core/results.rst.txt b/help/en/_sources/developer/core/results.rst.txt new file mode 100644 index 00000000..58e02560 --- /dev/null +++ b/help/en/_sources/developer/core/results.rst.txt @@ -0,0 +1,5 @@ +core.results +============ + +.. automodule:: core.results + :members: diff --git a/help/en/_sources/developer/hscommon/build.rst.txt b/help/en/_sources/developer/hscommon/build.rst.txt new file mode 100644 index 00000000..b3b106bd --- /dev/null +++ b/help/en/_sources/developer/hscommon/build.rst.txt @@ -0,0 +1,5 @@ +hscommon.build +============== + +.. automodule:: hscommon.build + :members: diff --git a/help/en/_sources/developer/hscommon/conflict.rst.txt b/help/en/_sources/developer/hscommon/conflict.rst.txt new file mode 100644 index 00000000..34724d10 --- /dev/null +++ b/help/en/_sources/developer/hscommon/conflict.rst.txt @@ -0,0 +1,5 @@ +hscommon.conflict +================= + +.. automodule:: hscommon.conflict + :members: diff --git a/help/en/_sources/developer/hscommon/desktop.rst.txt b/help/en/_sources/developer/hscommon/desktop.rst.txt new file mode 100644 index 00000000..e30ccafd --- /dev/null +++ b/help/en/_sources/developer/hscommon/desktop.rst.txt @@ -0,0 +1,5 @@ +hscommon.desktop +================ + +.. automodule:: hscommon.desktop + :members: diff --git a/help/en/_sources/developer/hscommon/gui/base.rst.txt b/help/en/_sources/developer/hscommon/gui/base.rst.txt new file mode 100644 index 00000000..0a20b963 --- /dev/null +++ b/help/en/_sources/developer/hscommon/gui/base.rst.txt @@ -0,0 +1,12 @@ +hscommon.gui.base +================= + +.. automodule:: hscommon.gui.base + + .. autosummary:: + + GUIObject + + .. autoclass:: GUIObject + :members: + :private-members: diff --git a/help/en/_sources/developer/hscommon/gui/column.rst.txt b/help/en/_sources/developer/hscommon/gui/column.rst.txt new file mode 100644 index 00000000..5780a19d --- /dev/null +++ b/help/en/_sources/developer/hscommon/gui/column.rst.txt @@ -0,0 +1,25 @@ +hscommon.gui.column +============================ + +.. automodule:: hscommon.gui.column + + .. autosummary:: + + Columns + Column + ColumnsView + PrefAccessInterface + + .. autoclass:: Columns + :members: + :private-members: + + .. autoclass:: Column + :members: + :private-members: + + .. autoclass:: ColumnsView + :members: + + .. autoclass:: PrefAccessInterface + :members: diff --git a/help/en/_sources/developer/hscommon/gui/progress_window.rst.txt b/help/en/_sources/developer/hscommon/gui/progress_window.rst.txt new file mode 100644 index 00000000..2453b705 --- /dev/null +++ b/help/en/_sources/developer/hscommon/gui/progress_window.rst.txt @@ -0,0 +1,18 @@ +hscommon.gui.progress_window +============================ + +.. automodule:: hscommon.gui.progress_window + + .. autosummary:: + + ProgressWindow + ProgressWindowView + + .. autoclass:: ProgressWindow + :members: + :private-members: + + .. autoclass:: ProgressWindowView + :members: + :private-members: + diff --git a/help/en/_sources/developer/hscommon/gui/selectable_list.rst.txt b/help/en/_sources/developer/hscommon/gui/selectable_list.rst.txt new file mode 100644 index 00000000..e9d6c9c1 --- /dev/null +++ b/help/en/_sources/developer/hscommon/gui/selectable_list.rst.txt @@ -0,0 +1,26 @@ +hscommon.gui.selectable_list +============================ + +.. automodule:: hscommon.gui.selectable_list + + .. autosummary:: + + Selectable + SelectableList + GUISelectableList + GUISelectableListView + + .. autoclass:: Selectable + :members: + :private-members: + + .. autoclass:: SelectableList + :members: + :private-members: + + .. autoclass:: GUISelectableList + :members: + :private-members: + + .. autoclass:: GUISelectableListView + :members: diff --git a/help/en/_sources/developer/hscommon/gui/table.rst.txt b/help/en/_sources/developer/hscommon/gui/table.rst.txt new file mode 100644 index 00000000..6f539d04 --- /dev/null +++ b/help/en/_sources/developer/hscommon/gui/table.rst.txt @@ -0,0 +1,26 @@ +hscommon.gui.table +================== + +.. automodule:: hscommon.gui.table + + .. autosummary:: + + Table + Row + GUITable + GUITableView + + .. autoclass:: Table + :members: + :private-members: + + .. autoclass:: Row + :members: + :private-members: + + .. autoclass:: GUITable + :members: + :private-members: + + .. autoclass:: GUITableView + :members: diff --git a/help/en/_sources/developer/hscommon/gui/text_field.rst.txt b/help/en/_sources/developer/hscommon/gui/text_field.rst.txt new file mode 100644 index 00000000..7f142bc0 --- /dev/null +++ b/help/en/_sources/developer/hscommon/gui/text_field.rst.txt @@ -0,0 +1,16 @@ +hscommon.gui.text_field +======================= + +.. automodule:: hscommon.gui.text_field + + .. autosummary:: + + TextField + TextFieldView + + .. autoclass:: TextField + :members: + :private-members: + + .. autoclass:: TextFieldView + :members: diff --git a/help/en/_sources/developer/hscommon/gui/tree.rst.txt b/help/en/_sources/developer/hscommon/gui/tree.rst.txt new file mode 100644 index 00000000..1c1e02b2 --- /dev/null +++ b/help/en/_sources/developer/hscommon/gui/tree.rst.txt @@ -0,0 +1,18 @@ +hscommon.gui.tree +================= + +.. automodule:: hscommon.gui.tree + + .. autosummary:: + + Tree + Node + + .. autoclass:: Tree + :members: + :private-members: + + .. autoclass:: Node + :members: + :private-members: + diff --git a/help/en/_sources/developer/hscommon/index.rst.txt b/help/en/_sources/developer/hscommon/index.rst.txt new file mode 100644 index 00000000..4fc45f97 --- /dev/null +++ b/help/en/_sources/developer/hscommon/index.rst.txt @@ -0,0 +1,16 @@ +hscommon +======== + +.. toctree:: + :maxdepth: 2 + :glob: + + build + conflict + desktop + notify + path + util + jobprogress/* + gui/* + diff --git a/help/en/_sources/developer/hscommon/jobprogress/job.rst.txt b/help/en/_sources/developer/hscommon/jobprogress/job.rst.txt new file mode 100644 index 00000000..af1553f8 --- /dev/null +++ b/help/en/_sources/developer/hscommon/jobprogress/job.rst.txt @@ -0,0 +1,17 @@ +hscommon.jobprogress.job +======================== + +.. automodule:: hscommon.jobprogress.job + + .. autosummary:: + + Job + NullJob + + .. autoclass:: Job + :members: + :private-members: + + .. autoclass:: NullJob + :members: + diff --git a/help/en/_sources/developer/hscommon/jobprogress/performer.rst.txt b/help/en/_sources/developer/hscommon/jobprogress/performer.rst.txt new file mode 100644 index 00000000..8a9ead0a --- /dev/null +++ b/help/en/_sources/developer/hscommon/jobprogress/performer.rst.txt @@ -0,0 +1,12 @@ +hscommon.jobprogress.performer +============================== + +.. automodule:: hscommon.jobprogress.performer + + .. autosummary:: + + ThreadedJobPerformer + + .. autoclass:: ThreadedJobPerformer + :members: + diff --git a/help/en/_sources/developer/hscommon/jobprogress/qt.rst.txt b/help/en/_sources/developer/hscommon/jobprogress/qt.rst.txt new file mode 100644 index 00000000..e7fd1df5 --- /dev/null +++ b/help/en/_sources/developer/hscommon/jobprogress/qt.rst.txt @@ -0,0 +1,12 @@ +hscommon.jobprogress.qt +======================= + +.. automodule:: hscommon.jobprogress.qt + + .. autosummary:: + + Progress + + .. autoclass:: Progress + :members: + diff --git a/help/en/_sources/developer/hscommon/notify.rst.txt b/help/en/_sources/developer/hscommon/notify.rst.txt new file mode 100644 index 00000000..4d61d584 --- /dev/null +++ b/help/en/_sources/developer/hscommon/notify.rst.txt @@ -0,0 +1,5 @@ +hscommon.notify +=============== + +.. automodule:: hscommon.notify + :members: diff --git a/help/en/_sources/developer/hscommon/path.rst.txt b/help/en/_sources/developer/hscommon/path.rst.txt new file mode 100644 index 00000000..e2bcab3d --- /dev/null +++ b/help/en/_sources/developer/hscommon/path.rst.txt @@ -0,0 +1,5 @@ +hscommon.path +============= + +.. automodule:: hscommon.path + :members: diff --git a/help/en/_sources/developer/hscommon/util.rst.txt b/help/en/_sources/developer/hscommon/util.rst.txt new file mode 100644 index 00000000..3dc3f539 --- /dev/null +++ b/help/en/_sources/developer/hscommon/util.rst.txt @@ -0,0 +1,5 @@ +hscommon.util +============= + +.. automodule:: hscommon.util + :members: diff --git a/help/en/_sources/developer/index.rst.txt b/help/en/_sources/developer/index.rst.txt new file mode 100644 index 00000000..0c9699c5 --- /dev/null +++ b/help/en/_sources/developer/index.rst.txt @@ -0,0 +1,74 @@ +Developer Guide +=============== + +When looking at a non-trivial codebase for the first time, it's very difficult to understand +anything of it until you get the "Big Picture". This page is meant to, hopefully, make you get +dupeGuru's big picture. + +Branches and tags +----------------- + +The git repo has one main branch, ``master``. It represents the latest "stable development commit", +that is, the latest commit that doesn't include in-progress features. This branch should always +be buildable, ``tox`` should always run without errors on it. + +When a feature/bugfix has an atomicity of a single commit, it's alright to commit right into +``master``. However, if a feature/bugfix needs more than a commit, it should live in a separate +topic branch until it's ready. + +Every release is tagged with the version number. For example, there's a ``2.8.2`` tag for the +v2.8.2 release. + +Model/View/Controller... nope! +------------------------------ + +dupeGuru's codebase has quite a few design flaws. The Model, View and Controller roles are filled by +different classes, scattered around. If you're aware of that, it might help you to understand what +the heck is going on. + +The central piece of dupeGuru is :class:`core.app.DupeGuru`. It's the only +interface to the python's code for the GUI code. A duplicate scan is started with +:meth:`core.app.DupeGuru.start_scanning()`, directories are added through +:meth:`core.app.DupeGuru.add_directory()`, etc.. + +A lot of functionalities of the App are implemented in the platform-specific subclasses of +:class:`core.app.DupeGuru`, like ``DupeGuru`` in ``cocoa/inter/app.py``, or the ``DupeGuru`` class +in ``qt/base/app.py``. For example, when performing "Remove Selected From Results", +``RemoveSelected()`` on the cocoa side, and ``remove_duplicates()`` on the PyQt side, are +respectively called to perform the thing. + +.. _jobs: + +Jobs +---- + +A lot of operations in dupeGuru take a significant amount of time. This is why there's a generalized +threaded job mechanism built-in :class:`~core.app.DupeGuru`. First, :class:`~core.app.DupeGuru` has +a ``progress`` member which is an instance of +:class:`~hscommon.jobprogress.performer.ThreadedJobPerformer`. It lets the GUI code know of the progress +of the current threaded job. When :class:`~core.app.DupeGuru` needs to start a job, it calls +``_start_job()`` and the platform specific subclass deals with the details of starting the job. + +Core principles +--------------- + +The core of the duplicate matching takes place (for SE and ME, not PE) in :mod:`core.engine`. +There's :func:`core.engine.getmatches` which take a list of :class:`core.fs.File` instances and +return a list of ``(firstfile, secondfile, match_percentage)`` matches. Then, there's +:func:`core.engine.get_groups` which takes a list of matches and returns a list of +:class:`.Group` instances (a :class:`.Group` is basically a list of :class:`.File` matching +together). + +When a scan is over, the final result (the list of groups from :func:`.get_groups`) is placed into +:attr:`core.app.DupeGuru.results`, which is a :class:`core.results.Results` instance. The +:class:`~.Results` instance is where all the dupe marking, sorting, removing, power marking, etc. +takes place. + +API +--- + +.. toctree:: + :maxdepth: 2 + + core/index + hscommon/index diff --git a/help/en/_sources/faq.rst.txt b/help/en/_sources/faq.rst.txt new file mode 100644 index 00000000..1fe9da40 --- /dev/null +++ b/help/en/_sources/faq.rst.txt @@ -0,0 +1,184 @@ +Frequently Asked Questions +========================== + +.. contents:: + +What is dupeGuru? +----------------- + +dupeGuru is a tool to find duplicate files on your computer. It has three operational modes: +Standard, Music and Picture. Each mode has its own specialized preferences. + +Each mode has multiple scan types, such as filename, contents, tags. Some scan types feature +advanced fuzzy matching algorithm, allowing you to find duplicates that other more rigid duplicate +scanners can't. + +What makes it special? +---------------------- + +It's mostly about customizability. There's a lot of scanning options that allow you to get the +type of results you're really looking for. + +How safe is it to use dupeGuru? +------------------------------- + +Very safe. dupeGuru has been designed to make sure you don't delete files you didn't mean to delete. +First, there is the reference folder system that lets you define folders where you absolutely +**don't** want dupeGuru to let you delete files there, and then there is the group reference system +that makes sure that you will **always** keep at least one member of the duplicate group. + +How can I report a bug a suggest a feature? +------------------------------------------- + +dupeGuru is hosted on `Github`_ and it's also where issues are tracked. The best way to report a +bug or suggest a feature is to sign up on Github and `open an issue`_. + +The mark box of a file I want to delete is disabled. What must I do? +-------------------------------------------------------------------- + +You cannot mark the reference (The first file) of a duplicate group. However, what you can do is to +promote a duplicate file to reference. Thus, if a file you want to mark is reference, select a +duplicate file in the group that you want to promote to reference, and click on +**Actions-->Make Selected into Reference**. If the reference file is from a reference folder +(filename written in blue letters), you cannot remove it from the reference position. + +I have a folder from which I really don't want to delete files. +--------------------------------------------------------------- + +If you want to be sure that dupeGuru will never delete file from a particular folder, make sure to +set its state to **Reference** at :doc:`folders`. + +What is this '(X discarded)' notice in the status bar? +------------------------------------------------------ + +In some cases, some matches are not included in the final results for security reasons. Let me use +an example. We have 3 file: A, B and C. We scan them using a low filter hardness. The scanner +determines that A matches with B, A matches with C, but B does **not** match with C. Here, dupeGuru +has kind of a problem. It cannot create a duplicate group with A, B and C in it because not all +files in the group would match together. It could create 2 groups: one A-B group and then one A-C +group, but it will not, for security reasons. Lets think about it: If B doesn't match with C, it +probably means that either B, C or both are not actually duplicates. If there would be 2 groups (A-B +and A-C), you would end up delete both B and C. And if one of them is not a duplicate, that is +really not what you want to do, right? So what dupeGuru does in a case like this is to discard the +A-C match (and adds a notice in the status bar). Thus, if you delete B and re-run a scan, you will +have a A-C match in your next results. + +I want to mark all files from a specific folder. What can I do? +--------------------------------------------------------------- + +Enable the :doc:`Dupes Only ` mode and click on the Folder column to sort your duplicates +by folder. It will then be easy for you to select all duplicates from the same folder, and then +press Space to mark all selected duplicates. + +I want to remove all files that are more than 300 KB away from their reference file. What can I do? +--------------------------------------------------------------------------------------------------- + +* Enable the :doc:`Dupes Only ` mode. +* Enable the **Delta Values** mode. +* Click on the "Size" column to sort the results by size. +* Select all duplicates below -300. +* Click on **Remove Selected from Results**. +* Select all duplicates over 300. +* Click on **Remove Selected from Results**. + +I want to make my latest modified files reference files. What can I do? +----------------------------------------------------------------------- + +* Enable the :doc:`Dupes Only ` mode. +* Enable the **Delta Values** mode. +* Click on the "Modification" column to sort the results by modification date. +* Click on the "Modification" column again to reverse the sort order. +* Select all duplicates over 0. +* Click on **Make Selected into Reference**. + +I want to mark all duplicates containing the word "copy". How do I do that? +--------------------------------------------------------------------------- + +* Type "copy" in the "Filter" field in the top-right corner of the result window. +* Click on **Mark --> Mark All**. + +I want to remove all songs that are more than 3 seconds away from their reference file. What can I do? +------------------------------------------------------------------------------------------------------ + +* Enable the :doc:`Dupes Only ` mode. +* Enable the **Delta Values** mode. +* Click on the "Time" column to sort the results by time. +* Select all duplicates below -00:03. +* Click on **Remove Selected from Results**. +* Select all duplicates over 00:03. +* Click on **Remove Selected from Results**. + +I want to make my highest bitrate songs reference files. What can I do? +----------------------------------------------------------------------- + +* Enable the :doc:`Dupes Only ` mode. +* Enable the **Delta Values** mode. +* Click on the "Bitrate" column to sort the results by bitrate. +* Click on the "Bitrate" column again to reverse the sort order. +* Select all duplicates over 0. +* Click on **Make Selected into Reference**. + +I don't want [live] and [remix] versions of my songs counted as duplicates. How do I do that? +--------------------------------------------------------------------------------------------- + +If your comparison threshold is low enough, you will probably end up with live and remix +versions of your songs in your results. There's nothing you can do to prevent that, but there's +something you can do to easily remove them from your results after the scan: post-scan +filtering. If, for example, you want to remove every song with anything inside square brackets +[]: + +* Type "[*]" in the "Filter" field in the top-right corner of the result window. +* Click on **Mark --> Mark All**. +* Click on **Actions --> Remove Selected from Results**. + +The "Filter Hardness" slider in the preferences won't move! +----------------------------------------------------------- + +This slider is only relevant for scan types that support "fuzziness". Many scan types, such as the +"Contents" type, only support exact matches. When these types are selected, the slider is disabled. + +On some OS, the fact that it's disabled is harder to see than on others, but if you can't move the +slider, it means that this preference is irrelevant in your current scan type. + +I've tried to send my duplicates to Trash, but dupeGuru is telling me it can't do it. Why? What can I do? +--------------------------------------------------------------------------------------------------------- + +Most of the time, the reason why dupeGuru can't send files to Trash is because of file permissions. +You need *write* permissions on files you want to send to Trash. + +If dupeGuru still gives you troubles after fixing your permissions, try enabling the "Directly +delete files" option that is offered to you when you activate Send to Trash. This will not send +files to the Trash, but delete them immediately. In some cases, for example on network storage +(NAS), this has been known to work when normal deletion didn't. + +If this fail, `HS forums`_ might be of some help. + +Why is Picture mode's contents scan so slow? +-------------------------------------------- + +This scanning method is very different from methods. It can detect duplicate photos even if they +are not exactly the same. This very cool capability has a cost: time. Every picture has to be +individually and fuzzily matched to all others, and this takes a lot of CPU power. + +If all you need to find is exact duplicates, just use the standard mode of dupeGuru with the +Contents scan method. If your photos have EXIF tags, you can also try the "EXIF" scan method which +is much faster. + +Where are user files located? +----------------------------- + +For some reason, you'd like to remove or edit dupeGuru's user files (debug logs, caches, etc.). +Where they're located depends on your platform: + +* Linux: ``~/.local/share/data/Hardcoded Software/dupeGuru`` +* Mac OS X: ``~/Library/Application Support/dupeGuru`` + +Preferences are stored elsewhere: + +* Linux: ``~/.config/Hardcoded Software/dupeGuru.conf`` +* Mac OS X: In the built-in ``defaults`` system, as ``com.hardcoded-software.dupeguru`` + +.. _HS forums: https://forum.hardcoded.net/ +.. _Github: https://github.com/hsoft/dupeguru +.. _open an issue: https://github.com/hsoft/dupeguru/wiki/issue-labels + diff --git a/help/en/_sources/folders.rst.txt b/help/en/_sources/folders.rst.txt new file mode 100644 index 00000000..1a080856 --- /dev/null +++ b/help/en/_sources/folders.rst.txt @@ -0,0 +1,76 @@ +Folder Selection +================ + +The first window you see when you launch dupeGuru is the folder selection window. This windows +contains the basic input dupeGuru needs to start a scan: + +* An Application Mode selection +* A Scan Type selection +* Folders to scan + +Application Mode +---------------- + +dupeGuru had three main modes: Standard, Music and Picture. + +Standard is for any type of files. This makes this mode the most polyvalent, but it lacks +specialized features other modes have. + +Music mode scans only music files, but it supports tags comparison and its results window has many +audio-related informational columns. + +Picture mode scans only pictures, but its contents scan type is a powerful fuzzy matcher that can +find pictures that are similar without being exactly the same. + +Choosing an application mode not only changes available scan types in the selector below, but also +changes available options in the preferences panel. Thus, if you want to fine tune your scan, be +sure to open the preferences panel **after** you've selected the application mode. + +Scan Type +--------- + +This selector determines the type of the scan we'll do. See :doc:`scan` for details about scan +types. + +Folder List +----------- + +To add a folder, click on the **+** button. If you added folder before, a popup +menu with a list of recent folders you added will pop. You can click on one of +them to add it directly to your list. If you click on the first item of the +popup menu, **Add New Folder...**, you will be prompted for a folder to add. If +you never added a folder, no menu will pop and you will directly be prompted +for a new folder to add. + +An alternate way to add folders to the list is to drag them in the list. + +To remove a folder, select the folder to remove and click on **-**. If a subfolder is selected when +you click the button, the selected folder will be set to **excluded** state (see below) instead of +being removed. + +Folder states +------------- + +Every folder can be in one of these 3 states: + +**Normal:** + Duplicates found in this folder can be deleted. +**Reference:** + Duplicates found in this folder **cannot** be deleted. Files from this folder can + only end up in **reference** position in the dupe group. If more than one file from reference + folders end up in the same dupe group, only one will be kept. The others will be removed from + the group. +**Excluded:** + Files in this directory will not be included in the scan. + +The default state of a folder is, of course, **Normal**. You can use **Reference** state for a +folder if you want to be sure that you won't delete any file from it. + +When you set the state of a directory, all subfolders of this folder automatically inherit this +state unless you explicitly set a subfolder's state. + +Scan +---- + +When you're ready, click on the **Scan** button to initiate the scanning process. When it's done, +you'll be shown the :doc:`results`. diff --git a/help/en/_sources/index.rst.txt b/help/en/_sources/index.rst.txt new file mode 100644 index 00000000..bda31538 --- /dev/null +++ b/help/en/_sources/index.rst.txt @@ -0,0 +1,45 @@ +dupeGuru help +============= + +This help document is also available in these languages: + +* `French `__ +* `German `__ +* `Armenian `__ +* `Russian `__ +* `Ukrainian `__ + +dupeGuru is a tool to find duplicate files on your computer. It has three +modes, Standard, Music and Picture, with each mode having its own scan types +and little features. + +Although dupeGuru can easily be used without documentation, reading this file +will help you to master it. If you are looking for guidance for your first +duplicate scan, you can take a look at the :doc:`Quick Start ` +section. + +It is a good idea to keep dupeGuru updated. You can download the latest version on its `homepage`_. + +Contents: + +.. toctree:: + :maxdepth: 2 + + contribute + quick_start + folders + preferences + scan + results + reprioritize + faq + developer/index + changelog + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` + +.. _homepage: https://www.hardcoded.net/dupeguru diff --git a/help/en/_sources/preferences.rst.txt b/help/en/_sources/preferences.rst.txt new file mode 100644 index 00000000..2c0cf43a --- /dev/null +++ b/help/en/_sources/preferences.rst.txt @@ -0,0 +1,78 @@ +Preferences +=========== + +**Tags to scan:** + When using the **Tags** scan type, you can select the tags that will be used for comparison. + +**Word weighting:** + See :ref:`word-weighting`. + +**Match similar words:** + See :ref:`similarity-matching`. + +**Match pictures of different dimensions:** + If you check this box, pictures of different dimensions will be allowed in the same + duplicate group. + +.. _filter-hardness: + +**Filter Hardness:** + The threshold needed for two files to be considered duplicates. A lower value means more + duplicates. The meaning of the threshold depends on the scanning type (see :doc:`scan`). + Only works for :ref:`worded ` and :ref:`picture blocks ` + scans. + +**Can mix file kind:** + If you check this box, duplicate groups are allowed to have files with different extensions. If + you don't check it, well, they aren't! + +**Ignore duplicates hardlinking to the same file:** + If this option is enabled, dupeGuru will verify duplicates to see if they refer to the same + `inode`_. If they do, they will not be considered duplicates. (Only for OS X and Linux) + +**Use regular expressions when filtering:** + If you check this box, the filtering feature will treat your filter query as a + **regular expression**. Explaining them is beyond the scope of this document. A good place to + start learning it is `regular-expressions.info`_. + +**Remove empty folders after delete or move:** + When this option is enabled, folders are deleted after a file is deleted or moved and the folder + is empty. + +**Copy and Move:** + Determines how the Copy and Move operations (in the Action menu) will behave. + +* **Right in destination:** All files will be sent directly in the selected destination, without + trying to recreate the source path at all. +* **Recreate relative path:** The source file's path will be re-created in the destination folder up + to the root selection in the Directories panel. For example, if you added + ``/Users/foobar/SomeFolder`` to your Directories panel and you move + ``/Users/foobar/SomeFolder/SubFolder/SomeFile.ext`` to the destination + ``/Users/foobar/MyDestination``, the final destination for the file will be + ``/Users/foobar/MyDestination/SubFolder`` (``SomeFolder`` has been trimmed from source's path in + the final destination.). +* **Recreate absolute path:** The source file's path will be re-created in the destination folder in + its entirety. For example, if you move ``/Users/foobar/SomeFolder/SubFolder/SomeFile.ext`` to the + destination ``/Users/foobar/MyDestination``, the final destination for the file will be + ``/Users/foobar/MyDestination/Users/foobar/SomeFolder/SubFolder``. + +In all cases, dupeGuru nicely handles naming conflicts by prepending a number to the destination +filename if the filename already exists in the destination. + +**Custom Command:** + This preference determines the command that will be invoked by the "Invoke Custom Command" + action. You can invoke any external application through this action. This can be useful if, + for example, you have a nice diffing application installed. + +The format of the command is the same as what you would write in the command line, except that there +are 2 placeholders: **%d** and **%r**. These placeholders will be replaced by the path of the +selected dupe (%d) and the path of the selected dupe's reference file (%r). + +If the path to your executable contains space characters, you should enclose it in "" quotes. You +should also enclose placeholders in quotes because it's very possible that paths to dupes and refs +will contain spaces. Here's an example custom command:: + + "C:\Program Files\SuperDiffProg\SuperDiffProg.exe" "%d" "%r" + +.. _inode: http://en.wikipedia.org/wiki/Inode +.. _regular-expressions.info: http://www.regular-expressions.info diff --git a/help/en/_sources/quick_start.rst.txt b/help/en/_sources/quick_start.rst.txt new file mode 100644 index 00000000..b9c5835e --- /dev/null +++ b/help/en/_sources/quick_start.rst.txt @@ -0,0 +1,14 @@ +Quick Start +=========== + +To get you quickly started with dupeGuru, let's just make a standard scan using default preferences. + +* Launch dupeGuru. +* Add folders to scan with either drag & drop or the "+" button. +* Click on **Scan**. +* Wait until the scan process is over. +* Look at every duplicate (The files that are indented) and verify that it is indeed a duplicate to the group's reference (The file above the duplicate that is not indented and have a disabled mark box). +* If a file is a false duplicate, select it and click on **Actions-->Remove Selected from Results**. +* Once you are sure that there is no false duplicate in your results, click on **Edit-->Mark All**, and then **Actions-->Send Marked to Recycle bin**. + +That is only a basic scan. There are a lot of tweaking you can do to get different results and several methods of examining and modifying your results. To know about them, just read the rest of this help file. diff --git a/help/en/_sources/reprioritize.rst.txt b/help/en/_sources/reprioritize.rst.txt new file mode 100644 index 00000000..4febfca4 --- /dev/null +++ b/help/en/_sources/reprioritize.rst.txt @@ -0,0 +1,25 @@ +Re-Prioritizing duplicates +========================== + +dupeGuru tries to automatically determine which duplicate should go in each group's reference +position, but sometimes it gets it wrong. In many cases, clever dupe sorting with "Delta Values" +and "Dupes Only" options in addition to the "Make Selected into Reference" action does the trick, +but sometimes, a more powerful option is needed. This is where the Re-Prioritization dialog comes +into play. You can summon it through the "Re-Prioritize Results" item in the "Actions" menu. + +This dialog allows you to select criteria according to which a reference dupe will be selected in +each dupe group. The list of available criteria is on the left and the list of criteria you've +selected is on the right. + +A criteria is a category followed by an argument. For example, "Size (Highest)" means that the dupe +with the biggest size will win. "Folder (/foo/bar)" means that dupes in this folder will win. To add +a criterion to the rightmost list, first select a category in the combobox, then select a +subargument in the list below, and then click on the right pointing arrow button. + +The order of the list on the right is important (you can re-order items through drag & drop). When +picking a dupe for reference position, the first criterion is used. If there's a tie, the second +criterion is used and so on and so on. For example, if your arguments are "Size (Highest)" and then +"Filename (Doesn't end with a number)", the reference file that will be picked in a group will be +the biggest file, and if two or more files have the same size, the one that has a filename that +doesn't end with a number will be used. When all criteria result in ties, the order in which dupes +previously were in the group will be used. \ No newline at end of file diff --git a/help/en/_sources/results.rst.txt b/help/en/_sources/results.rst.txt new file mode 100644 index 00000000..91778168 --- /dev/null +++ b/help/en/_sources/results.rst.txt @@ -0,0 +1,196 @@ +Results +======= + +.. contents:: + +When dupeGuru is finished scanning for duplicates, it will show its results in the form of duplicate group list. + +About duplicate groups +---------------------- + +A duplicate group is a group of files that all match together. Every group has a **reference file** and one or more **duplicate files**. The reference file is the first file of the group. Its mark box is disabled. Below it, and indented, are the duplicate files. + +You can mark duplicate files, but you can never mark the reference file of a group. This is a security measure to prevent dupeGuru from deleting not only duplicate files, but their reference. You sure don't want that, do you? + +What determines which files are reference and which files are duplicates is first their folder state. A file from a reference folder will always be reference in a duplicate group. If all files are from a normal folder, the size determine which file will be the reference of a duplicate group. dupeGuru assumes that you always want to keep the biggest file, so the biggest files will take the reference position. + +You can change the reference file of a group manually. To do so, select the duplicate file you want +to promote to reference, and click on **Actions-->Make Selected into Reference**. + +Reviewing results +----------------- + +Although you can just click on **Edit-->Mark All** and then **Actions-->Send Marked to Recycle bin** to quickly delete all duplicate files in your results, it is always recommended to review all duplicates before deleting them. + +To help you reviewing the results, you can bring up the **Details panel**. This panel shows all the details of the currently selected file as well as its reference's details. This is very handy to quickly determine if a duplicate really is a duplicate. You can also double-click on a file to open it with its associated application. + +If you have more false duplicates than true duplicates (If your filter hardness is very low), the best way to proceed would be to review duplicates, mark true duplicates and then click on **Actions-->Send Marked to Recycle bin**. If you have more true duplicates than false duplicates, you can instead mark all files that are false duplicates, and use **Actions-->Remove Marked from Results**. + +Marking and Selecting +--------------------- + +A **marked** duplicate is a duplicate with the little box next to it having a check-mark. A **selected** duplicate is a duplicate being highlighted. The multiple selection actions can be performed in dupeGuru in the standard way (Shift/Command/Control click). You can toggle all selected duplicates' mark state by pressing **space**. + +Show Dupes Only +--------------- + +When this mode is enabled, the duplicates are shown without their respective reference file. You can select, mark and sort this list, just like in normal mode. + +The dupeGuru results, when in normal mode, are sorted according to duplicate groups' **reference file**. This means that if you want, for example, to mark all duplicates with the "exe" extension, you cannot just sort the results by "Kind" to have all exe duplicates together because a group can be composed of more than one kind of files. That is where Dupes Only mode comes into play. To mark all your "exe" duplicates, you just have to: + +* Enable the Dupes Only mode. +* Add the "Kind" column with the "Columns" menu. +* Click on that "Kind" column to sort the list by kind. +* Locate the first duplicate with a "exe" kind. +* Select it. +* Scroll down the list to locate the last duplicate with a "exe" kind. +* Hold Shift and click on it. +* Press Space to mark all selected duplicates. + +.. _deltavalues: + +Delta Values +------------ + +If you turn this switch on, numerical columns will display the value relative to the duplicate's +reference instead of the absolute values. These delta values will also be displayed in a different +color, orange, so you can spot them easily. For example, if a duplicate is 1.2 MB and its reference +is 1.4 MB, the Size column will display -0.2 MB. + +Moreover, non-numerical values will also be in orange if their value is different from their +reference, and stay black if their value is the same. Combined with column sorting in Dupes Only +mode, this allows for very powerful post-scan filtering. + +Dupes Only and Delta Values +--------------------------- + +The Dupes Only mode unveil its true power when you use it with the Delta Values switch turned on. +When you turn it on, relative values will be displayed instead of absolute ones. So if, for example, +you want to remove from your results all duplicates that are more than 300 KB away from their +reference, you could sort the dupes only results by Size, select all duplicates under -300 in the +Size column, delete them, and then do the same for duplicates over 300 at the bottom of the list. + +Same thing for non-numerical values: When Dupes Only and Delta Values are enabled at the same time, +column sorting groups rows depending on whether they're orange or not. Example: You ran a contents +scan, but you would only like to delete duplicates that have the same filename? Sort by filename +and all dupes with their filename attribute being the same as the reference will be grouped +together, their value being in black. + +You could also use it to change the reference priority of your duplicate list. When you make a fresh +scan, if there are no reference folders, the reference file of every group is the biggest file. If +you want to change that, for example, to the latest modification time, you can sort the dupes only +results by modification time in **descending** order, select all duplicates with a modification time +delta value higher than 0 and click on **Make Selected into Reference**. The reason why you must +make the sort order descending is because if 2 files among the same duplicate group are selected +when you click on **Make Selected into Reference**, only the first of the list will be made +reference, the other will be ignored. And since you want the last modified file to be reference, +having the sort order descending assures you that the first item of the list will be the last +modified. + +Filtering +--------- + +dupeGuru supports post-scan filtering. With it, you can narrow down your results so you can perform +actions on a subset of it. For example, you could easily mark all duplicates with their filename +containing "copy" from your results using the filter. + +To use the filtering feature, type your filter in the "Filter" search field at the top-right corner +of the results window. What you type in that box will be applied to the *whole path* of every +duplicate in the results. Only duplicate *groups* having at least one duplicate matching the filter +will be shown. + +When having groups where not all duplicates match the filter, we still show all duplicates of +the group. However, non-matching duplicates are in "reference mode". Therefore, you can perform +actions like "Mark All" and be sure to only mark filtered duplicates. + +To go back to unfiltered result, blank out the field or click on the "X". + +In simple mode (the default mode), whatever you type as the filter is the string used to perform the +actual filtering, with the exception of one wildcard: **\***. Thus, if you type "[*]" as your +filter, it will match anything with [] brackets in it, whatever is in between those brackets. + +For more advanced filtering, you can turn "Use regular expressions when filtering" on. The filtering +feature will then use **regular expressions**. A regular expression is a language for matching text. +Explaining them is beyond the scope of this document. A good place to start learning it is +`regular-expressions.info`_. + +Matches are case insensitive in both simple and regexp mode. + +For the filter to match, your regular expression don't have to match the whole filename, it just +have to contain a string matching the expression. + +Action Menu +----------- + +**Clear Ignore List:** + Remove all ignored matches you added. You have to start a new scan for the + newly cleared ignore list to be effective. +**Export Results to XHTML:** + Take the current results, and create an XHTML file out of it. The + columns that are visible when you click on this button will be the columns present in the XHTML + file. The file will automatically be opened in your default browser. +**Send Marked to Trash:** + Send all marked duplicates to trash, obviously. Before proceeding, + you'll be presented deletion options (see below). +**Move Marked to...:** + Prompt you for a destination, and then move all marked files to that + destination. Source file's path might be re-created in destination, depending on the + "Copy and Move" preference. +**Copy Marked to...:** + Prompt you for a destination, and then copy all marked files to that + destination. Source file's path might be re-created in destination, depending on the + "Copy and Move" preference. +**Remove Marked from Results:** + Remove all marked duplicates from results. The actual files will + not be touched and will stay where they are. +**Remove Selected from Results:** + Remove all selected duplicates from results. Note that all + selected reference files will be ignored, only duplicates can be removed with this action. +**Make Selected into Reference:** + Promote all selected duplicates to reference. If a duplicate is + a part of a group having a reference file coming from a reference folder (in blue color), no + action will be taken for this duplicate. If more than one duplicate among the same group are + selected, only the first of each group will be promoted. +**Add Selected to Ignore List:** + This first removes all selected duplicates from results, and + then add the match of that duplicate and the current reference in the ignore list. This match + will not come up again in further scan. The duplicate itself might come back, but it will be + matched with another reference file. You can clear the ignore list with the Clear Ignore List + command. +**Open Selected with Default Application:** + Open the file with the application associated with selected file's type. +**Reveal Selected in Finder:** + Open the folder containing selected file. +**Invoke Custom Command:** + Invokes the external application you've set up in your preferences using the current selection + as arguments in the invocation. +**Rename Selected:** + Prompts you for a new name, and then rename the selected file. + +Deletion Options +---------------- + +These options affect how duplicate deletion takes place. Most of the time, you don't need to enable +any of them. + +**Link deleted files:** + The deleted files are replaced by a link to the reference file. You have a choice of replacing + it either with a `symlink`_ or a `hardlink`_. It's better to read the whole + wikipedia pages about them to make a informed choice, but in short, a symlink is a shortcut to + the file's path. If the original file is deleted or moved, the link is broken. A hardlink is a + link to the file *itself*. That link is as good as a "real" file. Only when *all* hardlinks to a + file are deleted is the file itself deleted. + + On OSX and Linux, this feature is supported fully, but under Windows, it's a bit complicated. + Windows XP doesn't support it, but Vista and up support it. However, for the feature to work, + dupeGuru has to run with administrative privileges. + +**Directly delete files:** + Instead of sending files to trash, directly delete them. This is used + for troubleshooting and you normally don't need to enable this unless dupeGuru has problems + deleting files normally, something that can happens when you try to delete files on network + storage (NAS). + +.. _regular-expressions.info: http://www.regular-expressions.info +.. _hardlink: http://en.wikipedia.org/wiki/Hard_link +.. _symlink: http://en.wikipedia.org/wiki/Symbolic_link diff --git a/help/en/_sources/scan.rst.txt b/help/en/_sources/scan.rst.txt new file mode 100644 index 00000000..fc9dc7e4 --- /dev/null +++ b/help/en/_sources/scan.rst.txt @@ -0,0 +1,168 @@ +The scanning process +==================== + +.. contents:: + +dupeGuru has 3 basic ways of scanning: :ref:`worded-scan` and :ref:`contents-scan` and +:ref:`picture blocks `. The first two types are for the Standard and Music +modes, the last is for the Picture mode. The scanning process is configured through the +:doc:`Preference pane `. + +.. _worded-scan: + +Worded scans +------------ + +Worded scans extract a string from each file and split it into words. The string can come from two +different sources: **Filename** or **Tags** (Music Edition only). + +When our source is music tags, we have to choose which tags to use. If, for example, we choose to +analyse *artist* and *title* tags, we'd end up with strings like +"The White Stripes - Seven Nation Army". + +Words are split by space characters, with all punctuation removed (some are replaced by spaces, some +by nothing) and all words lowercased. For example, the string "This guy's song(remix)" yields +*this*, *guys*, *song* and *remix*. + +Once this is done, the scanning dance begins. Finding duplicates is only a matter of finding how +many words in common two given strings have. If the :ref:`filter hardness ` is, +for example, ``80``, it means that 80% of the words of two strings must match. To determine the +matching percentage, dupeGuru first counts the total number of words in **both** strings, then count +the number of words matching (every word matching count as 2), and then divide the number of words +matching by the total number of words. If the result is higher or equal than the filter hardness, +we have a duplicate match. For example, "a b c d" and "c d e" have a matching percentage of 57 +(4 words matching, 7 total words). + +Fields +^^^^^^ + +Song filenames often come with multiple and distinct parts and this can cause problems. For example, +let's take these two songs: "Dolly Parton - I Will Always Love You" and +"Whitney Houston - I Will Always Love You". They are clearly not the same song (they come from +different artists), but they still still have a matching score of 71%! This means that, with a naive +scanning method, we would get these songs as a false positive as soon as we try to dig a bit deeper +in our dupe hunt by lowering the threshold a bit. + +This is why we have the "Fields" concept. Fields are separated by dashes (``-``). When the +"Filename - Fields" scan type is chosen, each field is compared separately. Our final matching score +will only be the lowest of all the fields. In our example, the title has a 100% match, but the +artist has a 0% match, making our final match score 0. + +Sometimes, our song filename policy isn't completely homogenous, which means that we can end up with +"The White Stripes - Seven Nation Army" and "Seven Nation Army - The White Stripes". This is why +we have the "Filename - Fields (No Order)" scan type. With this scan type, all fields are compared +with each other, and the highest score is kept. Then, the final matching score is the lowest of them +all. In our case, the final matching score is 100. + +Note: Each field is used once. Thus, "The White Stripes - The White Stripes" and +"The White Stripes - Seven Nation Army" have a match score of 0 because the second +"The White Stripes" can't be compared with the first field of the other name because it has already +been "used up" by the first field. Our final match score would be 0. + +*Tags* scanning method is always "fielded". When choosing this scan method, we also choose which +tags are going to be compared, each being a field. + +.. _word-weighting: + +Word weighting +^^^^^^^^^^^^^^ + +When enabled, this option slightly changes how matching percentage is calculated by making bigger +words worth more. With word weighting, instead of having a value of 1 in the duplicate count and +total word count, every word have a value equal to the number of characters they have. With word +weighting, "ab cde fghi" and "ab cde fghij" would have a matching percentage of 53% (19 total +characters, 10 characters matching (4 for "ab" and 6 for "cde")). + +.. _similarity-matching: + +Similarity matching +^^^^^^^^^^^^^^^^^^^ + +When enabled, similar words will be counted as matches. For example "The White Stripes" and +"The White Stripe" would have a match score of 100 instead of 66 with that option turned on. + +Two words are considered similar if they can be made equal with only a few edit operations (removing +a letter, adding one etc.). The process used is not unlike the +`Levenshtein distance`_. For the technically inclined, the actual function used is +Python's `get_close_matches`_ with a ``0.8`` cutoff. + +**Warning:** Use this option with caution. It is likely that you will get a lot of false positives +in your results when turning it on. However, it will help you to find duplicates that you wouldn't +have found otherwise. The scan process also is significantly slower with this option turned on. + +.. _contents-scan: + +Contents scans +-------------- + +Contents scans are much simpler than worded scans. We read files and if the contents is exactly the +same, we consider the two files duplicates. + +This is, of course, quite longer than comparing filenames and, to avoid needlessly reading whole +file contents, we start by looking at file sizes. After having grouped our files by size, we discard +every file that is alone in its group. Then, we proceed to read the contents of our remaining files. + +MD5 hashes are used to compute compare contents. Yes, it is widely known that forging files having +the same MD5 hash is easy, but this file has to be knowingly forged. The possibilities of two files +having the same MD5 hash *and* the same size by accident is still very, very small. + +The :ref:`filter hardness ` preference is ignored in this scan. + +Folders +^^^^^^^ + +This is a special Contents scan type. It works like a normal contents scan, but +instead of trying to find duplicate files, it tries to find duplicate folders. +A folder is duplicate to another if all files it contains have the same +contents as the other folder's file. + +This scan is, of course, recursive and subfolders are checked. dupeGuru keeps only the biggest +fishes. Therefore, if two folders that are considered as matching contain subfolders, these +subfolders will not be included in the final results. + +With this mode, we end up with folders as results instead of files. + +.. _picture-blocks-scan: + +Picture blocks +-------------- + +dupeGuru Picture mode stands apart of its two friends. Its scan types are completely different. +The first one is its "Contents" scan, which is a bit too generic, hence the name we use here, +"Picture blocks". + +We start by opening every picture in RGB bitmap mode, then we "blockify" the picture. We create a +15x15 grid and compute the average color of each grid tile. This is the "picture analysis" phase. +It's very time consuming and the result is cached in a database (the "picture cache"). + +Once we've done that, we can start comparing them. Each tile in the grid (an average color) is +compared to its corresponding grid on the other picture and a color diff is computer (it's simply +a sum of the difference of R, G and B on each side). All these sums are added up to a final "score". + +If that score is smaller or equal to ``100 - threshold``, we have a match. + +A threshold of 100 adds an additional constraint that pictures have to be exactly the same (it's +possible, due to averaging, that the tile comparison yields ``0`` for pictures that aren't exactly +the same, but since "100%" suggests "exactly the same", we discard those ocurrences). If you want +to get pictures that are very, very similar but still allow a bit of fuzzy differences, go for 99%. + +This second part of the scan is CPU intensive and can take quite a bit of time. This task has been +made to take advatange of multi-core CPUs and has been optimized to the best of my abilities, but +the fact of the matter is that, due to the fuzziness of the task, we still have to compare every picture +to every other, making the algorithm quadratic (if ``N`` is the number of pictures to compare, the +number of comparisons to perform is ``N*N``). + +This algorithm is very naive, but in the field, it works rather well. If you master a better +algorithm and want to improve dupeGuru, by all means, let me know! + +EXIF Timestamp +-------------- + +This one is easy. We read the EXIF information of every picture and extract the ``DateTimeOriginal`` +tag. If the tag is the same for two pictures, they're considered duplicates. + +**Warning:** Modified pictures often keep the same EXIF timestamp, so watch out for false positives +when you use that scan type. + +.. _Levenshtein distance: http://en.wikipedia.org/wiki/Levenshtein_distance +.. _get_close_matches: http://docs.python.org/3/library/difflib.html#difflib.get_close_matches diff --git a/help/en/_static/ajax-loader.gif b/help/en/_static/ajax-loader.gif new file mode 100644 index 00000000..61faf8ca Binary files /dev/null and b/help/en/_static/ajax-loader.gif differ diff --git a/help/en/_static/alert_info_32.png b/help/en/_static/alert_info_32.png new file mode 100644 index 00000000..ea4d1baf Binary files /dev/null and b/help/en/_static/alert_info_32.png differ diff --git a/help/en/_static/alert_warning_32.png b/help/en/_static/alert_warning_32.png new file mode 100644 index 00000000..a687c3dc Binary files /dev/null and b/help/en/_static/alert_warning_32.png differ diff --git a/help/en/_static/basic.css b/help/en/_static/basic.css new file mode 100644 index 00000000..c7adab45 --- /dev/null +++ b/help/en/_static/basic.css @@ -0,0 +1,665 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 59em; + max-width: 70em; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/help/en/_static/bg-page.png b/help/en/_static/bg-page.png new file mode 100644 index 00000000..fe0a6dc8 Binary files /dev/null and b/help/en/_static/bg-page.png differ diff --git a/help/en/_static/bullet_orange.png b/help/en/_static/bullet_orange.png new file mode 100644 index 00000000..1cb8097c Binary files /dev/null and b/help/en/_static/bullet_orange.png differ diff --git a/help/en/_static/comment-bright.png b/help/en/_static/comment-bright.png new file mode 100644 index 00000000..15e27edb Binary files /dev/null and b/help/en/_static/comment-bright.png differ diff --git a/help/en/_static/comment-close.png b/help/en/_static/comment-close.png new file mode 100644 index 00000000..4d91bcf5 Binary files /dev/null and b/help/en/_static/comment-close.png differ diff --git a/help/en/_static/comment.png b/help/en/_static/comment.png new file mode 100644 index 00000000..dfbc0cbd Binary files /dev/null and b/help/en/_static/comment.png differ diff --git a/help/en/_static/doctools.js b/help/en/_static/doctools.js new file mode 100644 index 00000000..0c15c009 --- /dev/null +++ b/help/en/_static/doctools.js @@ -0,0 +1,311 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var bbox = span.getBBox(); + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + var parentOfText = node.parentNode.parentNode; + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); \ No newline at end of file diff --git a/help/en/_static/documentation_options.js b/help/en/_static/documentation_options.js new file mode 100644 index 00000000..7665e710 --- /dev/null +++ b/help/en/_static/documentation_options.js @@ -0,0 +1,9 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: '', + VERSION: '4.0.3', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' +}; \ No newline at end of file diff --git a/help/en/_static/down-pressed.png b/help/en/_static/down-pressed.png new file mode 100644 index 00000000..5756c8ca Binary files /dev/null and b/help/en/_static/down-pressed.png differ diff --git a/help/en/_static/down.png b/help/en/_static/down.png new file mode 100644 index 00000000..1b3bdad2 Binary files /dev/null and b/help/en/_static/down.png differ diff --git a/help/en/_static/file.png b/help/en/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/help/en/_static/file.png differ diff --git a/help/en/_static/haiku.css b/help/en/_static/haiku.css new file mode 100644 index 00000000..75af2a5c --- /dev/null +++ b/help/en/_static/haiku.css @@ -0,0 +1,376 @@ +/* + * haiku.css_t + * ~~~~~~~~~~~ + * + * Sphinx stylesheet -- haiku theme. + * + * Adapted from http://haiku-os.org/docs/Haiku-doc.css. + * Original copyright message: + * + * Copyright 2008-2009, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Francois Revol + * Stephan Assmus + * Braden Ewing + * Humdinger + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +html { + margin: 0px; + padding: 0px; + background: #FFF url(bg-page.png) top left repeat-x; +} + +body { + line-height: 1.5; + margin: auto; + padding: 0px; + font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; + min-width: 59em; + max-width: 70em; + color: #333333; +} + +div.footer { + padding: 8px; + font-size: 11px; + text-align: center; + letter-spacing: 0.5px; +} + +/* link colors and text decoration */ + +a:link { + font-weight: bold; + text-decoration: none; + color: #dc3c01; +} + +a:visited { + font-weight: bold; + text-decoration: none; + color: #892601; +} + +a:hover, a:active { + text-decoration: underline; + color: #ff4500; +} + +/* Some headers act as anchors, don't give them a hover effect */ + +h1 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h2 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h3 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h4 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +a.headerlink { + color: #a7ce38; + padding-left: 5px; +} + +a.headerlink:hover { + color: #a7ce38; +} + +/* basic text elements */ + +div.content { + margin-top: 20px; + margin-left: 40px; + margin-right: 40px; + margin-bottom: 50px; + font-size: 0.9em; +} + +/* heading and navigation */ + +div.header { + position: relative; + left: 0px; + top: 0px; + height: 85px; + /* background: #eeeeee; */ + padding: 0 40px; +} +div.header h1 { + font-size: 1.6em; + font-weight: normal; + letter-spacing: 1px; + color: #0c3762; + border: 0; + margin: 0; + padding-top: 15px; +} +div.header h1 a { + font-weight: normal; + color: #0c3762; +} +div.header h2 { + font-size: 1.3em; + font-weight: normal; + letter-spacing: 1px; + text-transform: uppercase; + color: #aaa; + border: 0; + margin-top: -3px; + padding: 0; +} + +div.header img.rightlogo { + float: right; +} + + +div.title { + font-size: 1.3em; + font-weight: bold; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-bottom: 25px; +} +div.topnav { + /* background: #e0e0e0; */ +} +div.topnav p { + margin-top: 0; + margin-left: 40px; + margin-right: 40px; + margin-bottom: 0px; + text-align: right; + font-size: 0.8em; +} +div.bottomnav { + background: #eeeeee; +} +div.bottomnav p { + margin-right: 40px; + text-align: right; + font-size: 0.8em; +} + +a.uplink { + font-weight: normal; +} + + +/* contents box */ + +table.index { + margin: 0px 0px 30px 30px; + padding: 1px; + border-width: 1px; + border-style: dotted; + border-color: #e0e0e0; +} +table.index tr.heading { + background-color: #e0e0e0; + text-align: center; + font-weight: bold; + font-size: 1.1em; +} +table.index tr.index { + background-color: #eeeeee; +} +table.index td { + padding: 5px 20px; +} + +table.index a:link, table.index a:visited { + font-weight: normal; + text-decoration: none; + color: #dc3c01; +} +table.index a:hover, table.index a:active { + text-decoration: underline; + color: #ff4500; +} + + +/* Haiku User Guide styles and layout */ + +/* Rounded corner boxes */ +/* Common declarations */ +div.admonition { + -webkit-border-radius: 10px; + -khtml-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; + border-style: dotted; + border-width: thin; + border-color: #dcdcdc; + padding: 10px 15px 10px 15px; + margin-bottom: 15px; + margin-top: 15px; +} +div.note { + padding: 10px 15px 10px 80px; + background: #e4ffde url(alert_info_32.png) 15px 15px no-repeat; + min-height: 42px; +} +div.warning { + padding: 10px 15px 10px 80px; + background: #fffbc6 url(alert_warning_32.png) 15px 15px no-repeat; + min-height: 42px; +} +div.seealso { + background: #e4ffde; +} + +/* More layout and styles */ +h1 { + font-size: 1.3em; + font-weight: bold; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-top: 30px; +} + +h2 { + font-size: 1.2em; + font-weight: normal; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-top: 30px; +} + +h3 { + font-size: 1.1em; + font-weight: normal; + color: #0c3762; + margin-top: 30px; +} + +h4 { + font-size: 1.0em; + font-weight: normal; + color: #0c3762; + margin-top: 30px; +} + +p { + text-align: justify; +} + +p.last { + margin-bottom: 0; +} + +ol { + padding-left: 20px; +} + +ul { + padding-left: 5px; + margin-top: 3px; +} + +li { + line-height: 1.3; +} + +div.content ul > li { + -moz-background-clip:border; + -moz-background-inline-policy:continuous; + -moz-background-origin:padding; + background: transparent url(bullet_orange.png) no-repeat scroll left 0.45em; + list-style-image: none; + list-style-type: none; + padding: 0 0 0 1.666em; + margin-bottom: 3px; +} + +td { + vertical-align: top; +} + +code { + background-color: #e2e2e2; + font-size: 1.0em; + font-family: monospace; +} + +pre { + border-color: #0c3762; + border-style: dotted; + border-width: thin; + margin: 0 0 12px 0; + padding: 0.8em; + background-color: #f0f0f0; +} + +hr { + border-top: 1px solid #ccc; + border-bottom: 0; + border-right: 0; + border-left: 0; + margin-bottom: 10px; + margin-top: 20px; +} + +/* printer only pretty stuff */ +@media print { + .noprint { + display: none; + } + /* for acronyms we want their definitions inlined at print time */ + acronym[title]:after { + font-size: small; + content: " (" attr(title) ")"; + font-style: italic; + } + /* and not have mozilla dotted underline */ + acronym { + border: none; + } + div.topnav, div.bottomnav, div.header, table.index { + display: none; + } + div.content { + margin: 0px; + padding: 0px; + } + html { + background: #FFF; + } +} + +.viewcode-back { + font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; + margin: -1px -10px; + padding: 0 12px; +} + +/* math display */ +div.math p { + text-align: center; +} \ No newline at end of file diff --git a/help/en/_static/jquery-3.2.1.js b/help/en/_static/jquery-3.2.1.js new file mode 100644 index 00000000..d2d8ca47 --- /dev/null +++ b/help/en/_static/jquery-3.2.1.js @@ -0,0 +1,10253 @@ +/*! + * jQuery JavaScript Library v3.2.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2017-03-20T18:59Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.2.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Simple selector that can be filtered directly, removing non-Elements + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + // Complex selector, compare the two sets, removing non-Elements + qualifier = jQuery.filter( qualifier, elements ); + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( jQuery.isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ jQuery.camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( jQuery.camelCase ); + } else { + key = jQuery.camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( ">tbody", elem )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i, + val = 0; + + // If we already have the right measurement, avoid augmentation + if ( extra === ( isBorderBox ? "border" : "content" ) ) { + i = 4; + + // Otherwise initialize for horizontal or vertical properties + } else { + i = name === "width" ? 1 : 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with computed style + var valueIsBorderBox, + styles = getStyles( elem ), + val = curCSS( elem, name, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Fall back to offsetWidth/Height when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + if ( val === "auto" ) { + val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + } + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnothtmlwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, isFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + +
+ + +
+

Changelog

+

About the word “crash”: When reading this changelog, you might be alarmed at the number of fixes +for “crashes”. Be aware that when the word “crash” is used here, it refers to “soft crashes” which +don’t cause the application to quit. You simply get an error window that asks you if you want to +send the crash report to Hardcoded Software. Crashes that cause the application to quit are called +“hard crashes” in this changelog.

+
+

4.0.3 (2016-11-24)

+
    +
  • Add new picture cache backend: shelve
  • +
  • Make shelve picture cache backend the active one on MacOS to fix #394 more +elegantly. [cocoa]
  • +
  • Remove Sparkle (auto-updates) due to technical limitations. [cocoa]
  • +
+
+
+

4.0.2 (2016-10-09)

+
    +
  • Fix systematic crash in Picture Mode under MacOS Sierra. (#394)
  • +
  • No change for Linux. Just keeping version in sync.
  • +
+
+
+

4.0.1 (2016-08-24)

+
    +
  • Add Greek localization, by Gabriel Koutilellis. (#382)
  • +
  • Fix localization base path. [qt] (#378)
  • +
  • Fix broken load results dialog. [qt]
  • +
  • Fix crash on load results. [cocoa] (#380)
  • +
  • Save preferences more predictably. [qt] (#379)
  • +
  • Fix picture mode’s fuzzy block scanner threshold. (#387)
  • +
+
+
+

4.0.0 (2016-07-01)

+
    +
  • Merge Standard, Music and Picture editions in the same application!
  • +
  • Improve documentation. (#294)
  • +
  • Add Polish, Korean, Spanish and Dutch localizations.
  • +
  • qt: Fix wrong use_regexp option propagation to core. (#295)
  • +
  • qt: Fix progress window mistakenly showing up on startup. (#357)
  • +
  • Bump Python requirement to v3.4.
  • +
  • Bump OS X requirement to 10.8
  • +
  • Drop Windows support, maybe temporarily. +Details <https://www.hardcoded.net/archive2015`#2015-11-01>`_
  • +
  • cocoa: Drop iPhoto, Aperture and iTunes support. Was unmaintained and obsolete.
  • +
  • Drop “Audio Contents” scan type. Was confusing and seldom useful.
  • +
  • Change license to GPLv3
  • +
+
+
+

3.9.1 (2014-10-17)

+
    +
  • Fixed AttributeError: 'ComboboxModel' object has no attribute 'reset'. [Linux, Windows] (#254)
  • +
  • Fixed PermissionError on saving results. (#266)
  • +
  • Fixed a build problem introduced by Sphinx 1.2.3.
  • +
  • Updated German localisation, by Frank Weber.
  • +
+
+
+

3.9.0 (2014-04-19)

+
    +
  • This is mostly a dependencies upgrade.
  • +
  • Upgraded to Python 3.3.
  • +
  • Upgraded to Qt 5.
  • +
  • Minimum Windows version is now Windows 7 64bit.
  • +
  • Minimum Ubuntu version is now 14.04.
  • +
  • Minimum OS X version is now 10.7 (Lion).
  • +
  • … But with a couple of little improvements.
  • +
  • Improved documentation.
  • +
  • Overwrite subfolders’ state when setting states in folder dialog (#248)
  • +
  • The error report dialog now brings the user to Github issues.
  • +
+
+
+

3.8.0 (2013-12-07)

+
    +
  • Disable symlink/hardlink deletion option when not relevant. (#247)
  • +
  • Make Cmd+A select all folders in the Folder Selection dialog. [Mac] (#228)
  • +
  • Make non-numeric delta comparison case insensitive. (#239)
  • +
  • Fix surrogate-related UnicodeEncodeError on CSV export. (#210)
  • +
  • Fixed crash on Dupe Count sorting with Delta + Dupes Only. (#238)
  • +
  • Improved documentation.
  • +
  • Important internal refactorings.
  • +
  • Dropped Ubuntu 12.04 and 12.10 support.
  • +
  • Removed the fairware dialog (More Info).
  • +
+
+
+

3.7.1 (2013-08-19)

+
    +
  • Fixed folder scan type, which was broken in v3.7.0.
  • +
+
+
+

3.7.0 (2013-08-17)

+
    +
  • Improved delta values to support non-numerical values. (#213)
  • +
  • Improved the Re-Prioritize dialog’s UI. (#224)
  • +
  • Added hardlink/symlink support on Windows Vista+. (#220)
  • +
  • Dropped 32bit support on Mac OS X.
  • +
  • Added Vietnamese localization by Phan Anh.
  • +
+
+
+

3.6.1 (2013-04-28)

+
    +
  • Improved “Make Selection Reference” to make it clearer. (#222)
  • +
  • Improved “Open Selected” to allow opening more than one file at once. (#142)
  • +
  • Fixed a few typos here and there. (#216 #225)
  • +
  • Tweaked the fairware dialog (More Info).
  • +
  • Added Arch Linux packaging
  • +
  • Added a 64-bit build for Windows.
  • +
  • Improved Russian localization by Kyrill Detinov.
  • +
  • Improved Brazilian localization by Victor Figueiredo.
  • +
+
+
+

3.6.0 (2012-08-08)

+
    +
  • Added “Export to CSV”. (#189)
  • +
  • Added “Replace with symlinks” to complement “Replace with hardlinks”. [Mac, Linux] (#194)
  • +
  • dupeGuru now tells how many duplicates were affected after each re-prioritization operation. (#204)
  • +
  • Added Longest/Shortest filename criteria in the re-prioritize dialog. (#198)
  • +
  • Fixed result table cells which mistakenly became writable in v3.5.0. [Mac] (#203)
  • +
  • Fixed “Rename Selected” which was broken since v3.5.0. [Mac] (#202)
  • +
  • Fixed a bug where “Reset to Defaults” in the Columns menu wouldn’t refresh menu items’ marked state.
  • +
  • Added Brazilian localization by Victor Figueiredo.
  • +
+
+
+

3.5.0 (2012-06-01)

+
    +
  • Added a Deletion Options panel.
  • +
  • Greatly improved memory usage for big scans.
  • +
  • Added a keybinding for the filter field. (#182) [Mac]
  • +
  • Upgraded minimum requirements for Ubuntu to 12.04.
  • +
+
+
+

3.4.1 (2012-04-14)

+
    +
  • Fixed the “Folders” scan type. [Mac]
  • +
  • Fixed localization issues. [Windows, Linux]
  • +
+
+
+

3.4.0 (2012-03-29)

+
    +
  • Improved results window UI. [Windows, Linux]
  • +
  • Added a dialog to edit the Ignore List.
  • +
  • Added the ability to sort results by “marked” status.
  • +
  • Fixed “Open with default application”. (#190)
  • +
  • Fixed a bug where there would be a false reporting of discarded matches. (#195)
  • +
  • Fixed various localization glitches.
  • +
  • Fixed hard crashes on crash reporting. (#196)
  • +
  • Fixed bug where the details panel would show up at inconvenient places in the screen. [Windows, Linux]
  • +
+
+
+

3.3.3 (2012-02-01)

+
    +
  • Fixed crash on adding some folders. [Mac OS X]
  • +
  • Added Ukrainian localization by Yuri Petrashko.
  • +
+
+
+

3.3.2 (2012-01-16)

+
    +
  • Fixed random hard crashes (yeah, again). [Mac OS X]
  • +
  • Fixed crash on Export to HTML. [Windows, Linux]
  • +
  • Added Armenian localization by Hrant Ohanyan.
  • +
  • Added Russian localization by Igor Pavlov.
  • +
+
+
+

3.3.1 (2011-12-02)

+
    +
  • Fixed a couple of nasty crashes.
  • +
+
+
+

3.3.0 (2011-11-30)

+
    +
  • Added multiple-selection in folder selection dialog for a more efficient folder removal. (#179)
  • +
  • Fixed a crash in the prioritize dialog. (#178)
  • +
  • Fixed a bug where mass marking with a filter would mark more than filtered duplicates. (#181)
  • +
  • Fixed random hard crashes. [Mac OS X] (#183 #184)
  • +
  • Added Czech localization by Aleš Nehyba.
  • +
  • Added Italian localization by Paolo Rossi.
  • +
+
+
+

3.2.1 (2011-10-02)

+
    +
  • Fixed a couple of broken action bindings from v3.2.0.
  • +
+
+
+

3.2.0 (2011-09-27)

+
    +
  • Added duplicate re-prioritization dialog. (#138)
  • +
  • Added font size preference for duplicate table. (#82)
  • +
  • Added Quicklook support. [Mac OS X] (#21)
  • +
  • Improved behavior of Mark Selected. (#139)
  • +
  • Improved filename sorting. (#169)
  • +
  • Added Chinese (Simplified) localization by Eric Dee.
  • +
  • Tweaked the fairware system.
  • +
  • Upgraded minimum requirements to OS X 10.6 and Ubuntu 11.04.
  • +
+
+
+

3.1.2 (2011-08-25)

+
    +
  • Fixed a bug preventing the Folders scan from working. (#172)
  • +
+
+
+

3.1.1 (2011-08-24)

+
    +
  • Added German localization by Gregor Tätzner.
  • +
  • Improved OS X Lion compatibility. [Mac OS X]
  • +
  • Made the file collection phase cancellable. (#168)
  • +
  • Fixed glitch in folder window upon selecting a folder state. [Windows, Linux] (#165)
  • +
  • Fixed a text coloring glitch in the results. (#156)
  • +
  • Fixed glitch in the sorting feature of the Folder column. (#161)
  • +
  • Make sure that saved results have the “.dupeguru” extension. [Linux] (#157)
  • +
+
+
+

3.1.0 (2011-04-16)

+
    +
  • Added the “Folders” scan type. (#89)
  • +
  • Fixed a couple of crashes. (#140 #149)
  • +
+
+
+

3.0.2 (2011-03-16)

+
    +
  • Fixed crash after removing marked dupes. (#140)
  • +
  • Fixed crash on error handling. [Windows] (#144)
  • +
  • Fixed crash on copy/move. [Windows] (#148)
  • +
  • Fixed crash when launching dupeGuru from a very long folder name. [Mac OS X] (#119)
  • +
  • Fixed a refresh bug in directory panel. (#153)
  • +
  • Improved reliability of the “Send to Trash” operation. [Linux]
  • +
  • Tweaked Fairware reminders.
  • +
+
+
+

3.0.1 (2011-01-27)

+
    +
  • Restored the context menu which had been broken in 3.0.0. [Mac OS X] (#133)
  • +
  • Fixed a bug where an “unsaved results” warning would be issued on quit even with empty results. (#134)
  • +
  • Removed focus from the cancel button in the progress dialog to avoid accidental cancellations. [Mac OS X] (#135)
  • +
  • Folders added through drag and drop are added to the recent folders list. (#136)
  • +
  • Added a debugging mode. (#132)
  • +
  • Fixed french localization glitches.
  • +
+
+
+

3.0.0 (2011-01-24)

+
    +
  • Re-designed the UI. (#129)
  • +
  • Internationalized dupeGuru and localized it to french. (#32)
  • +
  • Changed the format of the help file. (#130)
  • +
+
+
+

2.12.3 (2011-01-01)

+
    +
  • Fixed bug causing results to be corrupted after a scan cancellation. (#120)
  • +
  • Fixed crash when fetching Fairware unpaid hours. (#121)
  • +
  • Fixed crash when replacing files with hardlinks. (#122)
  • +
+
+
+

2.12.2 (2010-10-05)

+
    +
  • Fixed delta column colors which were broken since 2.12.0.
  • +
  • Fixed column sorting crash. (#108)
  • +
  • Fixed occasional crash during scan. (#106)
  • +
+
+
+

2.12.1 (2010-09-30)

+
    +
  • Re-licensed dupeGuru to BSD and made it Fairware.
  • +
+
+
+

2.12.0 (2010-09-26)

+
    +
  • Improved UI with a little revamp.
  • +
  • Added the possibility to place hardlinks to references after having deleted duplicates. [Mac OS X, Linux] (#91)
  • +
  • Added an option to ignore duplicates hardlinking to the same file. [Mac OS X, Linux] (#92)
  • +
  • Added multiple selection in the “Add Directory” dialog. [Mac OS X] (#105)
  • +
  • Fixed a bug preventing drag & drop from working in the Directories panel. [Windows, Linux]
  • +
+
+
+

2.11.1 (2010-08-26)

+
    +
  • Fixed HTML exporting which was broken in 2.11.0.
  • +
+
+
+

2.11.0 (2010-08-18)

+
    +
  • Added the ability to save results (and reload them) at arbitrary locations.
  • +
  • Improved the way reference files in dupe groups are chosen. (#15)
  • +
  • Remember size/position of all windows between launches. (#102)
  • +
  • Fixed a bug sometimes preventing dupeGuru from reloading previous results.
  • +
  • Fixed a bug sometimes causing the progress dialog to be stuck there. [Mac OS X] (#103)
  • +
  • Removed the Creation Date column, which wasn’t displaying the correct value anyway. (#101)
  • +
+
+
+

2.10.1 (2010-07-15)

+ +
+
+

2.10.0 (2010-04-13)

+
    +
  • Improved error messages when files can’t be sent to trash, moved or copied.
  • +
  • Added a custom command invocation action. (#12)
  • +
  • Filters are now applied on whole paths. (#4)
  • +
+
+
+

2.9.2 (2010-02-10)

+
    +
  • dupeGuru is now 64-bit on Mac OS X!
  • +
  • Fixed a crash upon quitting when support folder is not present. (#83)
  • +
  • Fixed a crash during sorting. (#85)
  • +
  • Fixed selection glitches, especially while renaming. (#93)
  • +
+
+
+

2.9.1 (2010-01-13)

+
    +
  • Improved memory usage for Contents scans. (#75)
  • +
  • Improved scanning speed when ref directories are involved. (#77)
  • +
  • Show a message dialog at the end of the scan if no duplicates are found. (#81)
  • +
  • Fixed a bug sometimes causing the small files threshold pref to be ignored. [Mac OS X] (#75)
  • +
+
+
+

2.9.0 (2009-11-03)

+
    +
  • Significantly improved speed and memory usage of big contents-based scans.
  • +
  • Added drag & drop support in the Directories panel. (#9)
  • +
  • Fixed a bug causing dupeGuru to be confused if a scanned file was moved during the scan. (#72)
  • +
  • Dropped support for Mac OS X 10.4 (Tiger)
  • +
+
+
+

2.8.2 (2009-10-14)

+
    +
  • Improved directory selection in the Directories panel (Windows). (#56)
  • +
  • Fixed a bug preventing dupeGuru from starting on certain machines (Windows). (#68)
  • +
  • Fixed a crash during very big scans. (#70)
  • +
+
+
+

2.8.1 (2009-10-02)

+
    +
  • Fixed crash with filtering when regular expressions were enabled. (#60)
  • +
  • Fixed crash when setting directories’ state. (Mac OS X) (#66)
  • +
  • Fixed crash with Make Reference when certain filters are applied. (Mac OS X) (#55)
  • +
  • Improved error handling during delete/move/copy actions. (#62 #65)
  • +
+
+
+

2.8.0 (2009-09-07)

+
    +
  • Added support for all kinds of bundle (not just applications) (Mac OS X) (#11)
  • +
  • Re-introduced the Export to XHTML feature to Windows. (#14)
  • +
  • Improved Export to XHTML speed. (#14)
  • +
  • Improved Contents scanning speed for large files. (#33)
  • +
  • Improved the grouping algorithm to reduce the number of discarded files in non-exact scans. (#51)
  • +
  • Stopped showing the same file on the 2 sides of the details panel when a ref file is selected. (#50)
  • +
  • Fixed crashes in the Directories panel. (#46)
  • +
+
+
+

2.7.3 (2009-06-20)

+
    +
  • +
    Fixed bugs with selection being jumpy during “Make Reference” actions and Power Marker
    +
    switches. (#3)
    +
    +
  • +
  • Fixed crash happening when a file with non-roman characters couldn’t be analyzed. (#30)
  • +
  • Fixed crash sometimes happening during the file collection phase in scanning. (#38)
  • +
  • Restored double-click and right-click behavior lost in the PyQt move (Windows). (#34 #35)
  • +
+
+
+

2.7.2 (2009-06-10)

+
    +
  • Fixed an occasional crash on Copy/Move operations. (#16)
  • +
  • Added automatic exclusion for sensible folders (like system folders). (#20)
  • +
  • Fixed an occasional crash when application files were part of the results (Mac OS X). (#25)
  • +
+
+
+

2.7.1 (2009-05-29)

+
    +
  • Fixed a bug causing crashes when having application files in the results.
  • +
  • Fixed a bug causing a GUI freeze at the beginning of a scan with a lot of files.
  • +
  • Fixed a bug that sometimes caused a crash when an action was cancelled, and then started again.
  • +
+
+
+

2.7.0 (2009-05-25)

+
    +
  • Converted the Windows GUI to Qt.
  • +
  • Improved the reliability of the scanning process.
  • +
+
+
+

2.6.1 (2009-03-27)

+
    +
  • Fixed an occasional crash caused by permission issues.
  • +
  • +
    Fixed a bug where the “X discarded” notice would show a too large number of discarded
    +
    duplicates.
    +
    +
  • +
+
+
+

2.6.0 (2008-09-10)

+
    +
  • Added a small file threshold preference.
  • +
  • Added a notice in the status bar when matches were discarded during the scan.
  • +
  • Improved duplicate prioritization (smartly chooses which file you will keep).
  • +
  • Improved scan progress feedback.
  • +
  • Improved responsiveness of the user interface for certain actions.
  • +
+
+
+

2.5.4 (2008-08-10)

+
    +
  • Improved the speed of results loading and saving.
  • +
  • Fixed a crash sometimes occurring during duplicate deletion.
  • +
+
+
+

2.5.3 (2008-07-08)

+
    +
  • Improved unicode handling for filenames. dupeGuru will now find a lot more duplicates if your files have non-ascii characters in it.
  • +
  • Fixed “Clear Ignore List” crash in Windows.
  • +
+
+
+

2.5.2 (2008-01-10)

+
    +
  • Improved the handling of low memory situations.
  • +
  • Improved the directory panel. The “Remove” button changes to “Put Back” when an excluded directory is selected.
  • +
  • Improved scan, delete and move speed in situations where there were a lot of duplicates.
  • +
  • Fixed occasional crashes when moving bundles (such as .app files).
  • +
  • Fixed occasional crashes when moving a lot of files at once.
  • +
+
+
+

2.5.1 (2007-11-22)

+
    +
  • Added the “Remove empty folders” option.
  • +
  • Fixed results load/save issues.
  • +
  • Fixed occasional status bar inaccuracies when the results are filtered.
  • +
+
+
+

2.5.0 (2007-09-15)

+
    +
  • Added post scan filtering.
  • +
  • Fixed issues with the rename feature under Windows
  • +
  • Fixed some user interface annoyances under Windows
  • +
+
+
+

2.4.8 (2007-04-14)

+
    +
  • Improved UI responsiveness (using threads) under Mac OS X.
  • +
  • Improved result load/save speed and memory usage.
  • +
+
+
+

2.4.7 (2007-03-10)

+
    +
  • Fixed a “bad file descriptor” error occasionally popping up.
  • +
  • Fixed a bug with non-latin directory names.
  • +
+
+
+

2.4.6 (2007-02-10)

+
    +
  • Added Re-orderable columns. In fact, I re-added the feature which was lost in the C# conversion in 2.4.0 (Windows).
  • +
  • Changed the behavior of the scanning engine when setting the hardness to 100. It will now only match files that have their words in the same order.
  • +
  • Fixed a bug with all the Delete/Move/Copy actions with certain kinds of files.
  • +
+
+
+

2.4.5 (2007-01-11)

+
    +
  • Fixed a bug with the Move action.
  • +
+
+
+

2.4.4 (2007-01-07)

+
    +
  • Fixed a “ghosting” bug. Dupes deleted by dupeGuru would sometimes come back in subsequent scans (Windows).
  • +
  • Fixed bugs sometimes making dupeGuru crash when marking a dupe (Windows).
  • +
  • Fixed some minor visual glitches (Windows).
  • +
+
+
+

2.4.3 (2006-12-08)

+
    +
  • Fixed a mishandling of “.app” files (OS X).
  • +
  • Fixed a bug preventing files from “reference” directories to be displayed in blue in the results (Windows).
  • +
  • Fixed a bug preventing some files to be sent to the recycle bin (Windows).
  • +
  • Fixed a bug in the packaging preventing certain Windows configurations to start dupeGuru at all.
  • +
+
+
+

2.4.2 (2006-11-18)

+
    +
  • Fixed a bug with directory states.
  • +
+
+
+

2.4.1 (2006-11-15)

+
    +
  • Fixed a bug causing the ignore list not to be saved.
  • +
  • Fixed a bug sometimes making delete and move operations stall.
  • +
+
+
+

2.4.0 (2006-11-10)

+
    +
  • Changed the Windows interface. It is now .NET based.
  • +
  • Added an auto-update feature to the windows version.
  • +
  • Changed the way power marking works. It is now a mode instead of a separate window.
  • +
  • Changed the “Size (MB)” column for a “Size (KB)” column. The values are now “ceiled” instead of rounded. Therefore, a size “0” is now really 0 bytes, not just a value too small to be rounded up. It is also the case for delta values.
  • +
  • Removed the min word length/count options. These came from Mp3 Filter, and just aren’t used anymore. Word weighting does pretty much the same job.
  • +
+
+
+

2.3.4 (2006-11-07)

+
    +
  • Improved speed and memory usage of the scanning engine, again. Does it mean there was a lot of improvements to be made? Nah…
  • +
+
+
+

2.3.3 (2006-11-02)

+
    +
  • Improved speed and memory usage of the scanning engine, especially when the scan results in a lot of duplicates.
  • +
  • Now I wonder if Sparkle is going to work well…
  • +
+
+
+

2.3.2 (2006-10-16)

+
    +
  • Added an auto-update feature in the Mac OS X version (with Sparkle).
  • +
  • Fixed a bug preventing some duplicate reports to be created correctly under Windows.
  • +
+
+
+

2.3.1 (2006-10-02)

+
    +
  • Fixed a bug preventing some duplicates to be found, especially when scanning lots of files.
  • +
+
+
+

2.3.0 (2006-09-22)

+
    +
  • Added XHTML export feature.
  • +
+
+
+

2.2.10 (2006-08-31)

+
    +
  • Added sticky columns.
  • +
  • Fixed an issue with file caching between scans.
  • +
  • Fixed an issue preventing some duplicates from being deleted/moved/copied.
  • +
+
+
+

2.2.9 (2006-08-27)

+
    +
  • Fixed an issue with ignore list and unicode.
  • +
  • Fixed an issue with file attribute fetching sometimes causing dupeGuru to crash.
  • +
  • Fixed an issue in the directories panel under Windows.
  • +
+
+
+

2.2.8 (2006-08-17)

+
    +
  • Fixed an issue in the duplicate seeking engine preventing some duplicates to be found.
  • +
+
+
+

2.2.7 (2006-08-12)

+
    +
  • Improved unicode support.
  • +
  • Improved the “Reveal in Finder” (“Open Containing Folder” in Windows) feature so it selects the file in the folder it opens.
  • +
+
+
+

2.2.6 (2006-08-07)

+
    +
  • Improved the ignore list system.
  • +
  • dupeGuru is now a Universal application on Mac OS X.
  • +
+
+
+

2.2.5 (2006-07-26)

+
    +
  • Improved application (.app) dupe detection on Mac OS X.
  • +
  • Fixed an issue that occasionally made dupeGuru crash on startup.
  • +
+
+
+

2.2.4 (2006-06-27)

+
    +
  • Fixed an issue with Move and Copy features.
  • +
+
+
+

2.2.3 (2006-06-15)

+
    +
  • Improved duplicate scanning speed.
  • +
  • Added a warning that a file couldn’t be renamed if a file with the same name already exists.
  • +
+
+
+

2.2.2 (2006-06-07)

+
    +
  • Added “Rename Selected” feature.
  • +
  • Fixed some minor issues with “Reload Last Results” feature.
  • +
  • Fixed ignore list issues.
  • +
+
+
+

2.2.1 (2006-05-22)

+
    +
  • Fixed occasional progress bar woes under Windows.
  • +
  • Fixed a bug in the registration system under Windows.
  • +
  • Nothing has been changed in the Mac OS X version, but I want to keep version in sync.
  • +
+
+
+

2.2.0 (2006-05-10)

+
    +
  • Added destination path re-creation options.
  • +
  • Added an ignore list.
  • +
  • Changed the main icon.
  • +
  • Improved dramatically the delta values feature.
  • +
+
+
+

2.1.2 (2006-04-18)

+
    +
  • Added the “Match similar words” option.
  • +
  • Fixed Power marking issues under Mac.
  • +
+
+
+

2.1.1 (2006-04-14)

+
    +
  • Added the “Display delta values” option.
  • +
  • Improved Power marking sorting speed under Mac.
  • +
  • Fixed Power marking sorting issues.
  • +
+
+
+

2.1.0 (2006-04-03)

+
    +
  • Added the Power Marker feature.
  • +
  • Fixed a column sorting bug. The results would sometimes lose their sort order.
  • +
  • Fixed a bug with the Make Reference feature. The results sometimes wasn’t correctly refreshed after the reference switch.
  • +
+
+
+

2.0.1 (2006-03-23)

+
    +
  • Fixed an issue occasionally occurring when trying to reload results from removable media that is no longer present.
  • +
+
+
+

2.0.0 (2006-03-17)

+
    +
  • Complete rewrite.
  • +
  • Now runs on Mac OS X.
  • +
+
+
+

1.0.0 (2004-09-24)

+
    +
  • Initial release.
  • +
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/contribute.html b/help/en/contribute.html new file mode 100644 index 00000000..21e9f695 --- /dev/null +++ b/help/en/contribute.html @@ -0,0 +1,128 @@ + + + + + + + + Contribute to dupeGuru — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

Contribute to dupeGuru

+

dupeGuru was started as shareware (thus proprietary) so it doesn’t have a legacy of +community-building. It’s been open source for a while now and, although I’ve (“I” being Virgil +Dupras, author of the software) always wanted to have people other than me working on dupeGuru, I’ve +failed at attracting them.

+

Since the end of 2013, I’ve been putting a lot of efforts into dupeGuru’s +developer documentation and I’m more serious about my commitment to create +a community around this project.

+

So, whatever your skills, if you’re interested in contributing to dupeGuru, please do so. Normally, +this documentation should be enough to get you started, but if it isn’t, then please, +let me know because it’s a problem that I’m committed to fix. If there’s any situation where you’d +wish to contribute but some doubt you’re having prevent you from going forward, please contact me. +I’d much prefer to spend the time figuring out with you whether (and how) you can contribute than +taking the chance of missing that opportunity.

+
+

Development process

+ +

dupeGuru’s source code is on Github and thus managed in a Git repository. At all times, you should +be able to build from source a fresh checkout of the master branch using instructions from the +README.md file at the root of this project. If you can’t, it’s a bug. Please report it.

+

master is the main development branch, and thus represents what going to be included in the +next feature release. When needed, we create maintenance branches for bugfixes of the current +feature release.

+

When implementing a big feature, it’s possible that it gets its own branch until +it’s stable enough to merge into master.

+

Every release is tagged, the tag name containing the edition (for old versions) and its version. +For example, release 6.6.0 of dupeGuru ME is tagged me6.6.0. Newer releases are tagged only +with the version number (because editions don’t exist anymore), for example 4.0.0.

+

Once you’re past building the software, the developer documentation should +be enough to get you started with actual development. Then again, proper documentation is a very +difficult task and, in the case of dupeGuru, this documentation was practically nonexistent until +late in the project, so it’s still lacking.

+

However, I’m committed to fix this situation, so if you’re in a situation where you lack proper +documentation to figure something out about this code, please contact me.

+
+
+

Tasks for non-developers

+

Create and comment issues. The single most useful way for a user who is not a developer to +contribute to a software project is by thoroughly documenting a bug or a feature request. Most of +the time, what we get as developers are emails like “the app crashes” and we spend a lot of time +trying to figure out the cause of that bug. By properly describing the nature and context of a crash +(we learn to do that with experience as a user who reports bugs), you help developers so immensely, +you have no idea.

+

It’s the same thing with feature requests. Description of a feature request, when thoughts have +already been given to how such a feature would fit in the current design, are precious to developers +and help them figure out a clear roadmap for the project.

+

So, even if you’re not a developer, you can always open a Github account and create/comment issues. +Your contribution will be much appreciated.

+

Documentation. This is a bit trickier because dupeGuru’s documentation is written with a rather +complex markup language, Sphinx (based on reST). To properly work within the documentation, +you have to know that language. I don’t think that learning this language is outside the realm of +possibility for a non-developer, but it might be a daunting task.

+

That being said, if it’s a minor modification to the documentation, nothing stops you from opening +an issue (there’s a label for documentation issues, so this kind of issue is relevant to the +tracker) describing the change you propose to make and I’ll be happy to make the change myself (if +relevant, of course).

+

Even if it’s a bigger contribution to the documentation you want to make, I probably wouldn’t mind +doing the formatting myself. But in that case, it’s better to contact me first to make sure that we +agree on what should be added to the documentation.

+

Translation. Creating or improving an existing translation is a very good way to contribute to +dupeGuru. For more information about how to do that, you can refer to the translator guide.

+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/core/app.html b/help/en/developer/core/app.html new file mode 100644 index 00000000..68bf8e3e --- /dev/null +++ b/help/en/developer/core/app.html @@ -0,0 +1,363 @@ + + + + + + + + core.app — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

core.app

+
+
+class core.app.DupeGuru(view)
+

Holds everything together.

+

Instantiated once per running application, it holds a reference to every high-level object +whose reference needs to be held: Results, +Directories, core.gui instances, etc..

+

It also hosts high level methods and acts as a coordinator for all those elements. This is why +some of its methods seem a bit shallow, like for example mark_all() and +remove_duplicates(). These methos are just proxies for a method in results, but +they are also followed by a notification call which is very important if we want GUI elements +to be correctly notified of a change in the data they’re presenting.

+
+
+directories
+

Instance of Directories. It holds the current folder selection.

+
+ +
+
+results
+

Instance of core.results.Results. Holds the results of the latest scan.

+
+ +
+
+selected_dupes
+

List of currently selected dupes from our results. Whenever the user changes its +selection at the UI level, result_table takes care of updating this attribute, so +you can trust that it’s always up-to-date.

+
+ +
+
+result_table
+

Instance of meta-gui table listing the results from results

+
+ +
+
+add_directory(d)
+

Adds folder d to directories.

+

Shows an error message dialog if something bad happens.

+ +++ + + + +
Parameters:d (str) – path of folder to add
+
+ +
+
+add_selected_to_ignore_list()
+

Adds selected_dupes to ignore_list.

+
+ +
+
+apply_filter(filter)
+

Apply a filter filter to the results so that it shows only dupe groups that match it.

+ +++ + + + +
Parameters:filter (str) – filter to apply
+
+ +
+
+copy_or_move_marked(copy)
+

Start an async move (or copy) job on marked duplicates.

+ +++ + + + +
Parameters:copy (bool) – If True, duplicates will be copied instead of moved
+
+ +
+
+delete_marked()
+

Start an async job to send marked duplicates to the trash.

+
+ +
+
+export_to_csv()
+

Export current results to CSV.

+

The columns and their order in the resulting CSV file is determined in the same way as in +export_to_xhtml().

+
+ +
+
+export_to_xhtml()
+

Export current results to XHTML.

+

The configuration of the result_table (columns order and visibility) is used to +determine how the data is presented in the export. In other words, the exported table in +the resulting XHTML will look just like the results table.

+
+ +
+
+invoke_custom_command()
+

Calls command in CustomCommand pref with %d and %r placeholders replaced.

+

Using the current selection, %d is replaced with the currently selected dupe and %r +is replaced with that dupe’s ref file. If there’s no selection, the command is not invoked. +If the dupe is a ref, %d and %r will be the same.

+
+ +
+
+load()
+

Load directory selection and ignore list from files in appdata.

+

This method is called during startup so that directory selection and ignore list, which +is persistent data, is the same as when the last session was closed (when save() was +called).

+
+ +
+
+load_from(filename)
+

Start an async job to load results from filename.

+ +++ + + + +
Parameters:filename (str) – path of the XML file (created with save_as()) to load
+
+ +
+
+make_selected_reference()
+

Promote selected_dupes to reference position within their respective groups.

+

Each selected dupe will become the ref of its group. If there’s +more than one dupe selected for the same group, only the first (in the order currently shown +in result_table) dupe will be promoted.

+
+ +
+
+mark_all()
+

Set all dupes in the results as marked.

+
+ +
+
+mark_dupe(dupe, marked)
+

Change marked status of dupe.

+ +++ + + + +
Parameters:
    +
  • dupe (File) – dupe to mark/unmark
  • +
  • marked (bool) – True = mark, False = unmark
  • +
+
+
+ +
+
+mark_invert()
+

Invert the marked state of all dupes in the results.

+
+ +
+
+mark_none()
+

Set all dupes in the results as unmarked.

+
+ +
+
+open_selected()
+

Open selected_dupes with their associated application.

+
+ +
+
+purge_ignore_list()
+

Remove files that don’t exist from ignore_list.

+
+ +
+
+remove_directories(indexes)
+

Remove root directories at indexes from directories.

+ +++ + + + +
Parameters:indexes (list of int) – Indexes of the directories to remove.
+
+ +
+
+remove_duplicates(duplicates)
+

Remove duplicates from results.

+

Calls remove_duplicates() and send appropriate notifications.

+ +++ + + + +
Parameters:duplicates (list of File) – duplicates to remove.
+
+ +
+
+remove_marked()
+

Removed marked duplicates from the results (without touching the files themselves).

+
+ +
+
+remove_selected()
+

Removed selected_dupes from the results (without touching the files themselves).

+
+ +
+
+rename_selected(newname)
+

Renames the selected dupes’s file to newname.

+

If there’s more than one selected dupes, the first one is used.

+ +++ + + + +
Parameters:newname (str) – The filename to rename the dupe’s file to.
+
+ +
+
+reprioritize_groups(sort_key)
+

Sort dupes in each group (in results) according to sort_key.

+

Called by the re-prioritize dialog. Calls prioritize() and, once +the sorting is done, show a message that confirms the action.

+ +++ + + + +
Parameters:sort_key (f(dupe)) – The key being sent to prioritize()
+
+ +
+
+save_as(filename)
+

Save results in filename.

+ +++ + + + +
Parameters:filename (str) – path of the file to save results (as XML) to.
+
+ +
+
+start_scanning()
+

Starts an async job to scan for duplicates.

+

Scans folders selected in directories and put the results in results

+
+ +
+
+without_ref(dupes)
+

Returns dupes with all reference elements removed.

+
+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/core/directories.html b/help/en/developer/core/directories.html new file mode 100644 index 00000000..8d522321 --- /dev/null +++ b/help/en/developer/core/directories.html @@ -0,0 +1,219 @@ + + + + + + + + core.directories — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

core.directories

+
+
+exception core.directories.AlreadyThereError
+

The path being added is already in the directory list

+
+ +
+
+exception core.directories.InvalidPathError
+

The path being added is invalid

+
+ +
+
+class core.directories.Directories
+

Holds user folder selection.

+

Manages the selection that the user make through the folder selection dialog. It also manages +folder states, and how recursion applies to them.

+

Then, when the user starts the scan, get_files() is called to retrieve all files (wrapped +in core.fs) that have to be scanned according to the chosen folders/states.

+
+
+add_path(path)
+

Adds path to self, if not already there.

+

Raises AlreadyThereError if path is already in self. If path is a directory +containing some of the directories already present in self, path will be added, but all +directories under it will be removed. Can also raise InvalidPathError if path +does not exist.

+ +++ + + + +
Parameters:path (Path) – path to add
+
+ +
+
+get_files(fileclasses=None, j=<hscommon.jobprogress.job.NullJob object>)
+

Returns a list of all files that are not excluded.

+

Returned files also have their is_ref attr set if applicable.

+
+ +
+
+get_folders(folderclass=None, j=<hscommon.jobprogress.job.NullJob object>)
+

Returns a list of all folders that are not excluded.

+

Returned folders also have their is_ref attr set if applicable.

+
+ +
+
+get_state(path)
+

Returns the state of path.

+ +++ + + + +
Return type:DirectoryState
+
+ +
+
+static get_subfolders()
+

Returns a sorted list of paths corresponding to subfolders in path.

+ +++ + + + + + +
Parameters:path (Path) – get subfolders from there
Return type:list of Path
+
+ +
+
+has_any_file()
+

Returns whether selected folders contain any file.

+

Because it stops at the first file it finds, it’s much faster than get_files().

+ +++ + + + +
Return type:bool
+
+ +
+
+load_from_file(infile)
+

Load folder selection from infile.

+ +++ + + + +
Parameters:infile (file) – path or file pointer to XML generated through save_to_file()
+
+ +
+
+save_to_file(outfile)
+

Save folder selection as XML to outfile.

+ +++ + + + +
Parameters:outfile (file) – path or file pointer to XML file to save to.
+
+ +
+
+set_state(path, state)
+

Set the state of folder at path.

+ +++ + + + +
Parameters:
    +
  • path (Path) – path of the target folder
  • +
  • state (DirectoryState) – state to set folder to
  • +
+
+
+ +
+ +
+
+class core.directories.DirectoryState
+

Enum describing how a folder should be considered.

+
    +
  • DirectoryState.Normal: Scan all files normally
  • +
  • DirectoryState.Reference: Scan files, but make sure never to delete any of them
  • +
  • DirectoryState.Excluded: Don’t scan this folder
  • +
+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/core/engine.html b/help/en/developer/core/engine.html new file mode 100644 index 00000000..d935d357 --- /dev/null +++ b/help/en/developer/core/engine.html @@ -0,0 +1,284 @@ + + + + + + + + core.engine — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

core.engine

+
+
+class core.engine.Match
+

Represents a match between two File.

+

Regarless of the matching method, when two files are determined to match, a Match pair is created, +which holds, of course, the two matched files, but also their match “level”.

+
+
+first
+

first file of the pair.

+
+ +
+
+second
+

second file of the pair.

+
+ +
+
+percentage
+

their match level according to the scan method which found the match. int from 1 to 100. For +exact scan methods, such as Contents scans, this will always be 100.

+
+ +
+ +
+
+class core.engine.Group
+

A group of File that match together.

+

This manages match pairs into groups and ensures that all files in the group match to each +other.

+
+
+ref
+

The “reference” file, which is the file among the group that isn’t going to be deleted.

+
+ +
+
+ordered
+

Ordered list of duplicates in the group (including the ref).

+
+ +
+
+unordered
+

Set duplicates in the group (including the ref).

+
+ +
+
+dupes
+

An ordered list of the group’s duplicate, without ref. Equivalent to +ordered[1:]

+
+ +
+
+percentage
+

Average match percentage of match pairs containing ref.

+
+ +
+
+add_match(match)
+

Adds match to internal match list and possibly add duplicates to the group.

+

A duplicate can only be considered as such if it matches all other duplicates in the group. +This method registers that pair (A, B) represented in match as possible candidates and, +if A and/or B end up matching every other duplicates in the group, add these duplicates to +the group.

+ +++ + + + +
Parameters:match (tuple) – pair of File to add
+
+ +
+
+discard_matches()
+

Remove all recorded matches that didn’t result in a duplicate being added to the group.

+

You can call this after the duplicate scanning process to free a bit of memory.

+
+ +
+
+get_match_of(item)
+

Returns the match pair between item and ref.

+
+ +
+
+prioritize(key_func, tie_breaker=None)
+

Reorders ordered according to key_func.

+ +++ + + + +
Parameters:
    +
  • key_func – Key (f(x)) to be used for sorting
  • +
  • tie_breaker – function to be used to select the reference position in case the top +duplicates have the same key_func() result.
  • +
+
+
+ +
+
+switch_ref(with_dupe)
+

Make the ref dupe of the group switch position with with_dupe.

+
+ +
+ +
+
+core.engine.build_word_dict(objects, j=<hscommon.jobprogress.job.NullJob object>)
+

Returns a dict of objects mapped by their words.

+

objects must have a words attribute being a list of strings or a list of lists of strings +(Fields).

+

The result will be a dict with words as keys, lists of objects as values.

+
+ +
+
+core.engine.compare(first, second, flags=())
+

Returns the % of words that match between first and second

+

The result is a int in the range 0..100. +first and second can be either a string or a list (of words).

+
+ +
+
+core.engine.compare_fields(first, second, flags=())
+

Returns the score for the lowest matching Fields.

+

first and second must be lists of lists of string. Each sub-list is then compared with +compare().

+
+ +
+
+core.engine.getmatches(objects, min_match_percentage=0, match_similar_words=False, weight_words=False, no_field_order=False, j=<hscommon.jobprogress.job.NullJob object>)
+

Returns a list of Match within objects after fuzzily matching their words.

+ +++ + + + +
Parameters:
    +
  • objects – List of File to match.
  • +
  • min_match_percentage (int) – minimum % of words that have to match.
  • +
  • match_similar_words (bool) – make similar words (see merge_similar_words()) match.
  • +
  • weight_words (bool) – longer words are worth more in match % computations.
  • +
  • no_field_order (bool) – match Fields regardless of their order.
  • +
  • j – A job progress instance.
  • +
+
+
+ +
+
+core.engine.getmatches_by_contents(files, j=<hscommon.jobprogress.job.NullJob object>)
+

Returns a list of Match within files if their contents is the same.

+ +++ + + + +
Parameters:j – A job progress instance.
+
+ +
+
+core.engine.get_groups(matches)
+

Returns a list of Group from matches.

+

Create groups out of match pairs in the smartest way possible.

+
+ +
+
+core.engine.merge_similar_words(word_dict)
+

Take all keys in word_dict that are similar, and merge them together.

+

word_dict has been built with build_word_dict(). Similarity is computed with Python’s +difflib.get_close_matches(), which computes the number of edits that are necessary to make +a word equal to the other.

+
+ +
+
+core.engine.reduce_common_words(word_dict, threshold)
+

Remove all objects from word_dict values where the object count >= threshold

+

word_dict has been built with build_word_dict().

+

The exception to this removal are the objects where all the words of the object are common. +Because if we remove them, we will miss some duplicates!

+
+ +
+

Fields

+

Fields are groups of words which each represent a significant part of the whole name. This concept +is sifnificant in music file names, where we often have names like “My Artist - a very long title +with many many words”.

+

This title has 10 words. If you run as scan with a bit of tolerance, let’s say 90%, you’ll be able +to find a dupe that has only one “many” in the song title. However, you would also get false +duplicates from a title like “My Giraffe - a very long title with many many words”, which is of +course a very different song and it doesn’t make sense to match them.

+

When matching by fields, each field (separated by “-“) is considered as a separate string to match +independently. After all fields are matched, the lowest result is kept. In the “Giraffe” example we +gave, the result would be 50% instead of 90% in normal mode.

+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/core/fs.html b/help/en/developer/core/fs.html new file mode 100644 index 00000000..4f936c14 --- /dev/null +++ b/help/en/developer/core/fs.html @@ -0,0 +1,161 @@ + + + + + + + + core.fs — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

core.fs

+
+
+exception core.fs.FSError(fsobject, parent=None)
+
+ +
+
+exception core.fs.AlreadyExistsError(fsobject, parent=None)
+

The directory or file name we’re trying to add already exists

+
+ +
+
+exception core.fs.InvalidPath(fsobject, parent=None)
+

The path of self is invalid, and cannot be worked with.

+
+ +
+
+exception core.fs.InvalidDestinationError(fsobject, parent=None)
+

A copy/move operation has been called, but the destination is invalid.

+
+ +
+
+exception core.fs.OperationError(fsobject, parent=None)
+

A copy/move/delete operation has been called, but the checkup after the +operation shows that it didn’t work.

+
+ +
+
+class core.fs.File(path)
+

Represents a file and holds metadata to be used for scanning.

+
+
+classmethod can_handle(path)
+

Returns whether this file wrapper class can handle path.

+
+ +
+
+get_display_info(group, delta)
+

Returns a display-ready dict of dupe’s data.

+
+ +
+ +
+
+class core.fs.Folder(path)
+

A wrapper around a folder path.

+

It has the size/md5 info of a File, but it’s value are the sum of its subitems.

+
+
+classmethod can_handle(path)
+

Returns whether this file wrapper class can handle path.

+
+ +
+ +
+
+core.fs.get_file(path, fileclasses=[<class 'core.fs.File'>])
+

Wraps path around its appropriate File class.

+

Whether a class is “appropriate” is decided by File.can_handle()

+ +++ + + + +
Parameters:
    +
  • path (Path) – path to wrap
  • +
  • fileclasses – List of candidate File classes
  • +
+
+
+ +
+
+core.fs.get_files(path, fileclasses=[<class 'core.fs.File'>])
+

Returns a list of File for each file contained in path.

+ +++ + + + +
Parameters:
    +
  • path (Path) – path to scan
  • +
  • fileclasses – List of candidate File classes
  • +
+
+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/core/gui/deletion_options.html b/help/en/developer/core/gui/deletion_options.html new file mode 100644 index 00000000..d5f90c42 --- /dev/null +++ b/help/en/developer/core/gui/deletion_options.html @@ -0,0 +1,151 @@ + + + + + + + + core.gui.deletion_options — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

core.gui.deletion_options

+
+
+class core.gui.deletion_options.DeletionOptions
+

Present the user with deletion options before proceeding.

+

When the user activates “Send to trash”, we present him with a couple of options that changes +the behavior of that deletion operation.

+
+
+show(mark_count)
+

Prompt the user with a modal dialog offering our deletion options.

+ +++ + + + + + + + +
Parameters:mark_count (int) – Number of dupes marked for deletion.
Return type:bool
Returns:Whether the user accepted the dialog (we cancel deletion if false).
+
+ +
+ +

Returns whether our platform supports symlinks.

+
+ +
+
+direct = None
+

Delete dupes directly and don’t send to trash. +bool. get/set

+
+ +
+ +

Replace deleted dupes with symlinks (or hardlinks) to the dupe group reference.

+

bool. get/set

+

Whether the link is a symlink or hardlink is decided by use_hardlinks.

+
+ +
+ +

Whether symlinks or hardlinks are used when doing link_deleted. +bool. get/set

+
+ +
+ +
+
+class core.gui.deletion_options.DeletionOptionsView
+

Expected interface for DeletionOptions’s view.

+

Not actually used in the code. For documentation purposes only.

+

Our view presents the user with an appropriate way (probably a mix of checkboxes and radio +buttons) to set the different flags in DeletionOptions. Note that +DeletionOptions.use_hardlinks is only relevant if DeletionOptions.link_deleted +is true. This is why we toggle the “enabled” state of that flag.

+

We expect the view to set DeletionOptions.link_deleted immediately as the user changes +its value because it will toggle set_hardlink_option_enabled()

+

Other than the flags, there’s also a prompt message which has a dynamic content, defined by +update_msg().

+
+ +

Enable or disable the widget controlling DeletionOptions.use_hardlinks.

+
+ +
+
+show()
+

Show the dialog in a modal fashion.

+

Returns whether the dialog was “accepted” (the user pressed OK).

+
+ +
+
+update_msg(msg: str)
+

Update the dialog’s prompt with str.

+
+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/core/gui/index.html b/help/en/developer/core/gui/index.html new file mode 100644 index 00000000..86243d90 --- /dev/null +++ b/help/en/developer/core/gui/index.html @@ -0,0 +1,78 @@ + + + + + + + + core.gui — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

core.gui

+
+

Meta GUI elements in dupeGuru

+

dupeGuru is designed with a cross-toolkit approach in mind. It means that its core code +(which doesn’t depend on any GUI toolkit) has elements which preformat core information in a way +that makes it easy for a UI layer to consume.

+

For example, we have ResultTable which takes information from +Results and mashes it in rows and columns which are ready to be fetched by +either Cocoa’s NSTableView or Qt’s QTableView. It tells them which cell is supposed to be +blue, which is supposed to be orange, does the sorting logic, holds selection, etc..

+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/core/index.html b/help/en/developer/core/index.html new file mode 100644 index 00000000..c60b2057 --- /dev/null +++ b/help/en/developer/core/index.html @@ -0,0 +1,80 @@ + + + + + + + + core — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/help/en/developer/core/results.html b/help/en/developer/core/results.html new file mode 100644 index 00000000..4a0b37a2 --- /dev/null +++ b/help/en/developer/core/results.html @@ -0,0 +1,209 @@ + + + + + + + + core.results — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

core.results

+
+
+class core.results.Results(app)
+

Manages a collection of duplicate Group.

+

This class takes care or marking, sorting and filtering duplicate groups.

+
+
+groups
+

The list of Group contained managed by this instance.

+
+ +
+
+dupes
+

A list of all duplicates (File instances), without ref, contained in the +currently managed groups.

+
+ +
+
+apply_filter(filter_str)
+

Applies a filter filter_str to groups

+

When you apply the filter, only dupes with the filename matching filter_str will be in +in the results. To cancel the filter, just call apply_filter with filter_str to None, +and the results will go back to normal.

+

If call apply_filter on a filtered results, the filter will be applied +on the filtered results.

+ +++ + + + +
Parameters:filter_str (str) – a string containing a regexp to filter dupes with.
+
+ +
+
+get_group_of_duplicate(dupe)
+

Returns Group in which dupe belongs.

+
+ +
+
+load_from_xml(infile, get_file, j=<hscommon.jobprogress.job.NullJob object>)
+

Load results from infile.

+ +++ + + + +
Parameters: +
+
+ +
+
+make_ref(dupe)
+

Make dupe take the ref position of its group.

+
+ +
+
+perform_on_marked(func, remove_from_results)
+

Performs func on all marked dupes.

+

If an EnvironmentError is raised during the call, the problematic dupe is added to +self.problems.

+ +++ + + + +
Parameters:remove_from_results (bool) – If true, dupes which had func applied and didn’t cause +any problem.
+
+ +
+
+remove_duplicates(dupes)
+

Remove dupes from their respective Group.

+

Also, remove the group from groups if it ends up empty.

+
+ +
+
+save_to_xml(outfile)
+

Save results to outfile in XML.

+ +++ + + + +
Parameters:outfile – file object or path.
+
+ +
+
+sort_dupes(key, asc=True, delta=False)
+

Sort dupes according to key.

+ +++ + + + +
Parameters:
    +
  • key (str) – key attribute name to sort with.
  • +
  • asc (bool) – If false, sorting is reversed.
  • +
  • delta (bool) – If true, sorting occurs using delta values.
  • +
+
+
+ +
+
+sort_groups(key, asc=True)
+

Sort groups according to key.

+

The ref of each group is used to extract values for sorting.

+ +++ + + + +
Parameters:
    +
  • key (str) – key attribute name to sort with.
  • +
  • asc (bool) – If false, sorting is reversed.
  • +
+
+
+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/build.html b/help/en/developer/hscommon/build.html new file mode 100644 index 00000000..11fde36f --- /dev/null +++ b/help/en/developer/hscommon/build.html @@ -0,0 +1,112 @@ + + + + + + + + hscommon.build — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.build

+

This module is a collection of function to help in HS apps build process.

+
+
+hscommon.build.add_to_pythonpath(path)
+

Adds path to both PYTHONPATH env and sys.path.

+
+ +
+
+hscommon.build.build_debian_changelog(changelogpath, destfile, pkgname, from_version=None, distribution='precise', fix_version=None)
+

Builds a debian changelog out of a YAML changelog.

+

Use fix_version to patch the top changelog to that version (if, for example, there was a +packaging error and you need to quickly fix it)

+
+ +
+
+hscommon.build.build_dmg(app_path, destfolder)
+

Builds a DMG volume with application at app_path and puts it in dest_path.

+

The name of the resulting DMG volume is determined by the app’s name and version.

+
+ +
+
+hscommon.build.copy_packages(packages_names, dest, create_links=False, extra_ignores=None)
+

Copy python packages packages_names to dest, spurious data.

+

Copy will happen without tests, testdata, mercurial data or C extension module source with it. +py2app include and exclude rules are quite funky, and doing this is the only reliable +way to make sure we don’t end up with useless stuff in our app.

+
+ +
+
+hscommon.build.ensure_empty_folder(path)
+

Make sure that the path exists and that it’s an empty folder.

+
+ +
+
+hscommon.build.filereplace(filename, outfilename=None, **kwargs)
+

Reads filename, replaces all {variables} in kwargs, and writes the result to outfilename.

+
+ +
+
+hscommon.build.print_and_do(cmd)
+

Prints cmd and executes it in the shell.

+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/conflict.html b/help/en/developer/hscommon/conflict.html new file mode 100644 index 00000000..c778046b --- /dev/null +++ b/help/en/developer/hscommon/conflict.html @@ -0,0 +1,98 @@ + + + + + + + + hscommon.conflict — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.conflict

+

When you have to deal with names that have to be unique and can conflict together, you can use +this module that deals with conflicts by prepending unique numbers in [] brackets to the name.

+
+
+hscommon.conflict.get_conflicted_name(other_names, name)
+

Returns name with a [000] number in front of it.

+

The number between brackets depends on how many conlicted filenames +there already are in other_names.

+
+ +
+
+hscommon.conflict.get_unconflicted_name(name)
+

Returns name without [] brackets.

+

Brackets which, of course, might have been added by func:get_conflicted_name.

+
+ +
+
+hscommon.conflict.is_conflicted(name)
+

Returns whether name is prepended with a bracketed number.

+
+ +
+
+hscommon.conflict.smart_copy(source_path, dest_path)
+

Copies source_path to dest_path, recursively and with conflict resolution.

+
+ +
+
+hscommon.conflict.smart_move(source_path, dest_path)
+

Same as smart_copy(), but it moves files instead.

+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/desktop.html b/help/en/developer/hscommon/desktop.html new file mode 100644 index 00000000..19f20db7 --- /dev/null +++ b/help/en/developer/hscommon/desktop.html @@ -0,0 +1,90 @@ + + + + + + + + hscommon.desktop — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.desktop

+
+
+hscommon.desktop.open_path(path)
+

Open path with its associated application.

+
+ +
+
+hscommon.desktop.open_url(url)
+

Open url with the default browser.

+
+ +
+
+hscommon.desktop.reveal_path(path)
+

Open the folder containing path with the default file browser.

+
+ +
+
+hscommon.desktop.special_folder_path(special_folder, appname=None)
+

Returns the path of special_folder.

+

special_folder is a SpecialFolder.* const. The result is the special folder for the current +application. The running process’ application info is used to determine relevant information.

+

You can override the application name with appname. This argument is ingored under Qt.

+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/gui/base.html b/help/en/developer/hscommon/gui/base.html new file mode 100644 index 00000000..536f8604 --- /dev/null +++ b/help/en/developer/hscommon/gui/base.html @@ -0,0 +1,116 @@ + + + + + + + + hscommon.gui.base — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.gui.base

+ ++++ + + + + + +
GUIObject([multibind])Cross-toolkit “model” representation of a GUI layer object.
+
+
+class hscommon.gui.base.GUIObject(multibind=False)
+

Cross-toolkit “model” representation of a GUI layer object.

+

A GUIObject is a cross-toolkit “model” representation of a GUI layer object, for example, a +table. It acts as a cross-toolkit interface to what we call here a view. That +view is a toolkit-specific controller to the actual view (an NSTableView, a QTableView, +etc.). In our GUIObject, we need a reference to that toolkit-specific controller because some +actions have effects on it (for example, prompting it to refresh its data). The GUIObject +is typically instantiated before its view, that is why we set it to None on init. +However, the GUI layer is supposed to set the view as soon as its toolkit-specific controller is +instantiated.

+

When you subclass GUIObject, you will likely want to update its view on instantiation. That +is why we call self.view.refresh() in _view_updated(). If you need another type of +action on view instantiation, just override the method.

+

Most of the time, you will only one to bind a view once in the lifetime of your GUI object. +That is why there are safeguards, when setting view to ensure that we don’t double-assign. +However, sometimes you want to be able to re-bind another view. In this case, set the +multibind flag to True and the safeguard will be disabled.

+
+
+_view_updated()
+

(Virtual) Called after view has been set.

+

Doing nothing by default, this method is called after view has been set (it isn’t +called when it’s unset, however). Use this for initialization code that requires a view +(which is often the whole of the initialization code).

+
+ +
+
+view
+

A reference to our toolkit-specific view controller.

+

view answering to GUIObject sublass’s view protocol. get/set

+

This view starts as None and has to be set “manually”. There’s two times at which we set +the view property: On initialization, where we set the view that we’ll use for our lifetime, +and just before the view is deallocated. We need to unset our view at that time to avoid +calls to a deallocated instance (which means a crash).

+

To unset our view, we simple assign it to None.

+
+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/gui/column.html b/help/en/developer/hscommon/gui/column.html new file mode 100644 index 00000000..07c949ff --- /dev/null +++ b/help/en/developer/hscommon/gui/column.html @@ -0,0 +1,367 @@ + + + + + + + + hscommon.gui.column — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.gui.column

+ ++++ + + + + + + + + + + + + + + +
Columns(table[, prefaccess, savename])Cross-toolkit GUI-enabled column set for tables or outlines.
Column(name[, display, visible, optional])Holds column attributes such as its name, width, visibility, etc.
ColumnsViewExpected interface for Columns’s view.
PrefAccessInterfaceExpected interface for Columns’s prefaccess.
+
+
+class hscommon.gui.column.Columns(table, prefaccess=None, savename=None)
+

Cross-toolkit GUI-enabled column set for tables or outlines.

+

Manages a column set’s order, visibility and width. We also manage the persistence of these +attributes so that we can restore them on the next run.

+

Subclasses GUIObject. Expected view: ColumnsView.

+ +++ + + + +
Parameters:
    +
  • table – The table the columns belong to. It’s from there that we retrieve our column +configuration and it must have a COLUMNS attribute which is a list of +Column. We also call save_edits() on it from time to +time. Technically, this argument can also be a tree, but there’s probably some +sorting in the code to do to support this option cleanly.
  • +
  • prefaccess – An object giving access to user preferences for the currently running app. +We use this to make column attributes persistent. Must follow +PrefAccessInterface.
  • +
  • savename (str) – The name under which column preferences will be saved. This name is in fact +a prefix. Preferences are saved under more than one name, but they will all +have that same prefix.
  • +
+
+
+
+_view_updated()
+

(Virtual) Called after view has been set.

+

Doing nothing by default, this method is called after view has been set (it isn’t +called when it’s unset, however). Use this for initialization code that requires a view +(which is often the whole of the initialization code).

+
+ +
+
+column_by_index(index)
+

Return the Column having the logical_index index.

+
+ +
+
+column_by_name(name)
+

Return the Column having the name name.

+
+ +
+
+column_display(colname)
+

Returns display name for column named colname, or '' if there’s none.

+
+ +
+
+column_is_visible(colname)
+

Returns visibility for column named colname, or True if there’s none.

+
+ +
+
+column_width(colname)
+

Returns width for column named colname, or 0 if there’s none.

+
+ +
+
+columns_count()
+

Returns the number of columns in our set.

+
+ +
+
+columns_to_right(colname)
+

Returns the list of all columns to the right of colname.

+

“right” meaning “having a higher Column.ordered_index” in our left-to-right +civilization.

+
+ +
+
+menu_items()
+

Returns a list of items convenient for quick visibility menu generation.

+

Returns a list of (display_name, is_marked) items for each optional column in the +current view (is_marked means that it’s visible).

+

You can use this to generate a menu to let the user toggle the visibility of an optional +column. That is why we only show optional column, because the visibility of mandatory +columns can’t be toggled.

+
+ +
+
+move_column(colname, index)
+

Moves column colname to index.

+

The column will be placed just in front of the column currently having that index, or to the +end of the list if there’s none.

+
+ +
+
+reset_to_defaults()
+

Reset all columns’ width and visibility to their default values.

+
+ +
+
+resize_column(colname, newwidth)
+

Set column colname’s width to newwidth.

+
+ +
+
+restore_columns()
+

Restore’s column persistent attributes from the last save_columns().

+
+ +
+
+save_columns()
+

Save column attributes in persistent storage for restoration in restore_columns().

+
+ +
+
+set_column_order(colnames)
+

Change the columns order so it matches the order in colnames.

+ +++ + + + +
Parameters:colnames – A list of column names in the desired order.
+
+ +
+
+set_column_visible(colname, visible)
+

Set the visibility of column colname.

+
+ +
+
+set_default_width(colname, width)
+

Set the default width or column colname.

+
+ +
+
+toggle_menu_item(index)
+

Toggles the visibility of an optional column.

+

You know, that optional column menu you’ve generated in menu_items()? Well, index +is the index of them menu item in that menu that the user has clicked on to toggle it.

+

Returns whether the column in question ends up being visible or not.

+
+ +
+
+colnames
+

List of column names in visible order.

+
+ +
+
+ordered_columns
+

List of Column in visible order.

+
+ +
+ +
+
+class hscommon.gui.column.Column(name, display='', visible=True, optional=False)
+

Holds column attributes such as its name, width, visibility, etc.

+

These attributes are then used to correctly configure the column on the “view” side.

+
+
+default_visible = None
+

Whether the column is visible by default. It will be used if column restoration doesn’t +contain any “remembered” widths.

+
+ +
+
+default_width = None
+

Default width of the column. This value usually depends on the platform and is set on +columns initialisation. It will be used if column restoration doesn’t contain any +“remembered” widths.

+
+ +
+
+display = None
+

Display name (title) of the column.

+
+ +
+
+logical_index = None
+

Immutable index of the column. Doesn’t change even when columns are re-ordered. Used in +Columns.column_by_index().

+
+ +
+
+name = None
+

“programmatical” (not for display) name. Used as a reference in a couple of place, such +as Columns.column_by_name().

+
+ +
+
+optional = None
+

Whether the column can have visible set to false.

+
+ +
+
+ordered_index = None
+

Index of the column in the ordered set of columns.

+
+ +
+
+visible = None
+

Whether the column is visible.

+
+ +
+
+width = None
+

Width of the column.

+
+ +
+ +
+
+class hscommon.gui.column.ColumnsView
+

Expected interface for Columns’s view.

+

Not actually used in the code. For documentation purposes only.

+

Our view, the columns controller of a table or outline, is expected to properly respond to +callbacks.

+
+
+restore_columns()
+

Update all columns according to the model.

+

When this is called, our view has to update the columns title, order and visibility of all +columns.

+
+ +
+
+set_column_visible(colname, visible)
+

Update visibility of column colname.

+

Called when the user toggles the visibility of a column, we must update the column +colname’s visibility status to visible.

+
+ +
+ +
+
+class hscommon.gui.column.PrefAccessInterface
+

Expected interface for Columns’s prefaccess.

+

Not actually used in the code. For documentation purposes only.

+
+
+get_default(key, fallback_value)
+

Retrieve the value for key in the currently running app’s preference store.

+

If the key doesn’t exist, return fallback_value.

+
+ +
+
+set_default(key, value)
+

Set the value value for key in the currently running app’s preference store.

+
+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/gui/progress_window.html b/help/en/developer/hscommon/gui/progress_window.html new file mode 100644 index 00000000..5e4006e1 --- /dev/null +++ b/help/en/developer/hscommon/gui/progress_window.html @@ -0,0 +1,199 @@ + + + + + + + + hscommon.gui.progress_window — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.gui.progress_window

+ ++++ + + + + + + + + +
ProgressWindow(finish_func[, error_func])Cross-toolkit GUI-enabled progress window.
ProgressWindowViewExpected interface for ProgressWindow’s view.
+
+
+class hscommon.gui.progress_window.ProgressWindow(finish_func, error_func=None)
+

Cross-toolkit GUI-enabled progress window.

+

This class allows you to run a long running, job enabled function in a separate thread and +allow the user to follow its progress with a progress dialog.

+

To use it, you start your long-running job with run() and then have your UI layer +regularly call pulse() to refresh the job status in the UI. It is advised that you call +pulse() in the main thread because GUI toolkit usually only support calling UI-related +functions from the main thread.

+

We subclass GUIObject and ThreadedJobPerformer. +Expected view: ProgressWindowView.

+ +++ + + + +
Parameters:
    +
  • finish_func – A function f(jobid) that is called when a job is completed. jobid is +an arbitrary id passed to run().
  • +
  • error_func – A function f(jobid, err) that is called when an exception is raised and +unhandled during the job. If not specified, the error will be raised in the +main thread. If it’s specified, it’s your responsibility to raise the error +if you want to. If the function returns True, finish_func() will be +called as if the job terminated normally.
  • +
+
+
+
+cancel()
+

Call for a user-initiated job cancellation.

+
+ +
+
+pulse()
+

Update progress reports in the GUI.

+

Call this regularly from the GUI main run loop. The values might change before +ProgressWindowView.set_progress() happens.

+

If the job is finished, pulse() will take care of closing the window and re-raising any +exception that might have been raised during the job (in the main thread this time). If +there was no exception, finish_func(jobid) is called to let you take appropriate action.

+
+ +
+
+run(jobid, title, target, args=())
+

Starts a threaded job.

+

The target function will be sent, as its first argument, a Job instance which +it can use to report on its progress.

+ +++ + + + +
Parameters:
    +
  • jobid – Arbitrary identifier which will be passed to finish_func() at the end.
  • +
  • title – A title for the task you’re starting.
  • +
  • target – The function that does your famous long running job.
  • +
  • args – additional arguments that you want to send to target.
  • +
+
+
+ +
+
+jobdesc_textfield = None
+

TextField. It contains that title you gave the job on run().

+
+ +
+
+progressdesc_textfield = None
+

TextField. It contains the job textual update that the function might yield +during its course.

+
+ +
+ +
+
+class hscommon.gui.progress_window.ProgressWindowView
+

Expected interface for ProgressWindow’s view.

+

Not actually used in the code. For documentation purposes only.

+

Our view, some kind window with a progress bar, two labels and a cancel button, is expected +to properly respond to its callbacks.

+

It’s also expected to call ProgressWindow.cancel() when the cancel button is clicked.

+
+
+close()
+

Close the dialog.

+
+ +
+
+set_progress(progress)
+

Set the progress of the progress bar to progress.

+

Not all jobs are equally responsive on their job progress report and it is recommended that +you put your progressbar in “indeterminate” mode as long as you haven’t received the first +set_progress() call to avoid letting the user think that the app is frozen.

+ +++ + + + +
Parameters:progress (int) – a value between 0 and 100.
+
+ +
+
+show()
+

Show the dialog.

+
+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/gui/selectable_list.html b/help/en/developer/hscommon/gui/selectable_list.html new file mode 100644 index 00000000..28e286e7 --- /dev/null +++ b/help/en/developer/hscommon/gui/selectable_list.html @@ -0,0 +1,232 @@ + + + + + + + + hscommon.gui.selectable_list — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.gui.selectable_list

+ ++++ + + + + + + + + + + + + + + +
Selectable()Mix-in for a Sequence that manages its selection status.
SelectableList([items])A list that can manage selection of its items.
GUISelectableList([items])Cross-toolkit GUI-enabled list view.
GUISelectableListViewExpected interface for GUISelectableList’s view.
+
+
+class hscommon.gui.selectable_list.Selectable
+

Mix-in for a Sequence that manages its selection status.

+

When mixed in with a Sequence, we enable it to manage its selection status. The selection +is held as a list of int indexes. Multiple selection is supported.

+
+
+_update_selection()
+

(Virtual) Updates the model’s selection appropriately.

+

Called after selection has been updated. Takes the table’s selection and does appropriates +updates on the view and/or model. Common sense would dictate that when the selection doesn’t +change, we don’t update anything (and thus don’t call _update_selection() at all), but +there are cases where it’s false. For example, if our list updates its items but doesn’t +change its selection, we probably want to update the model’s selection.

+

By default, does nothing.

+

Important note: This is only called on select(), not on changes to +selected_indexes.

+
+ +
+
+select(indexes)
+

Update selection to indexes.

+

_update_selection() is called afterwards.

+ +++ + + + +
Parameters:indexes (list) – List of int that is to become the new selection.
+
+ +
+
+selected_index
+

Points to the first selected index.

+

int. get/set.

+

Thin wrapper around selected_indexes. None if selection is empty. Using this +property only makes sense if your selectable sequence supports single selection only.

+
+ +
+
+selected_indexes
+

List of selected indexes.

+

list of int. get/set.

+

When setting the value, automatically removes out-of-bounds indexes. The list is kept +sorted.

+
+ +
+ +
+
+class hscommon.gui.selectable_list.SelectableList(items=None)
+

A list that can manage selection of its items.

+

Subclasses Selectable. Behaves like a list.

+
+
+_on_change()
+

(Virtual) Called whenever the contents of the list changes.

+

By default, does nothing.

+
+ +
+
+append(item)
+

S.append(value) – append value to the end of the sequence

+
+ +
+
+insert(index, item)
+

S.insert(index, value) – insert value before index

+
+ +
+
+remove(row)
+

S.remove(value) – remove first occurrence of value. +Raise ValueError if the value is not present.

+
+ +
+ +
+
+class hscommon.gui.selectable_list.GUISelectableList(items=None)
+

Cross-toolkit GUI-enabled list view.

+

Represents a UI element presenting the user with a selectable list of items.

+

Subclasses SelectableList and GUIObject. Expected view: +GUISelectableListView.

+ +++ + + + +
Parameters:items (iterable) – If specified, items to fill the list with initially.
+
+
+_on_change()
+

Refreshes the view contents with GUISelectableListView.refresh().

+

Overrides SelectableList._on_change().

+
+ +
+
+_update_selection()
+

Refreshes the view selection with GUISelectableListView.update_selection().

+

Overrides Selectable._update_selection().

+
+ +
+
+_view_updated()
+

Refreshes the view contents with GUISelectableListView.refresh().

+

Overrides _view_updated().

+
+ +
+ +
+
+class hscommon.gui.selectable_list.GUISelectableListView
+

Expected interface for GUISelectableList’s view.

+

Not actually used in the code. For documentation purposes only.

+

Our view, some kind of list view or combobox, is expected to sync with the list’s contents by +appropriately behave to all callbacks in this interface.

+
+
+refresh()
+

Refreshes the contents of the list widget.

+

Ensures that the contents of the list widget is synced with the model.

+
+ +
+
+update_selection()
+

Update selection status.

+

Ensures that the list widget’s selection is in sync with the model.

+
+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/gui/table.html b/help/en/developer/hscommon/gui/table.html new file mode 100644 index 00000000..e3b6538f --- /dev/null +++ b/help/en/developer/hscommon/gui/table.html @@ -0,0 +1,441 @@ + + + + + + + + hscommon.gui.table — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.gui.table

+ ++++ + + + + + + + + + + + + + + +
Table()Sortable and selectable sequence of Row.
Row(table)Represents a row in a Table.
GUITable()Cross-toolkit GUI-enabled table view.
GUITableViewExpected interface for GUITable’s view.
+
+
+class hscommon.gui.table.Table
+

Sortable and selectable sequence of Row.

+

In fact, the Table is very similar to SelectableList in +practice and differs mostly in principle. Their difference lies in the nature of their items +they manage. With the Table, rows usually have many properties, presented in columns, and they +have to subclass Row.

+

Usually used with Column.

+

Subclasses Selectable.

+
+
+append(item)
+

Appends item at the end of the table.

+

If there’s a footer, the item is inserted before it.

+
+ +
+
+insert(index, item)
+

Inserts item at index in the table.

+

If there’s a header, will make sure we don’t insert before it, and if there’s a footer, will +make sure that we don’t insert after it.

+
+ +
+
+remove(row)
+

Removes row from table.

+

If row is a header or footer, that header or footer will be set to None.

+
+ +
+
+sort_by(column_name, desc=False)
+

Sort table by column_name.

+

Sort key for each row is computed from Row.sort_key_for_column().

+

If desc is True, sort order is reversed.

+

If present, header and footer will always be first and last, respectively.

+
+ +
+
+footer
+

If set, a row that always stay at the bottom of the table.

+

Row. get/set.

+

When set to something else than None, header and footer represent rows that will +always be kept in first and/or last position, regardless of sorting. len() and indexing +will include them, which means that if there’s a header, table[0] returns it and if +there’s a footer, table[-1] returns it. To make things short, all list-like functions +work with header and footer “on”. But things get fuzzy for append() and insert() +because these will ensure that no “normal” row gets inserted before the header or after the +footer.

+

Adding and removing footer here and there might seem (and is) hackish, but it’s much simpler +than the alternative (when, of course, you need such a feature), which is to override magic +methods and adjust the results. When we do that, there the slice stuff that we have to +implement and it gets quite complex. Moreover, the most frequent operation on a table is +__getitem__, and making checks to know whether the key is a header or footer at each +call would make that operation, which is the most used, slower.

+
+ +
+
+header
+

If set, a row that always stay at the bottom of the table.

+

See footer for details.

+
+ +
+
+row_count
+

Number or rows in the table (without counting header and footer).

+

int. read-only.

+
+ +
+
+rows
+

List of rows in the table, excluding header and footer.

+

List of Row. read-only.

+
+ +
+
+selected_row
+

Selected row according to Selectable.selected_index.

+

Row. get/set.

+

When setting this attribute, we look up the index of the row and set the selected index from +there. If the row isn’t in the list, selection isn’t changed.

+
+ +
+
+selected_rows
+

List of selected rows based on selected_indexes.

+

List of Row. read-only.

+
+ +
+ +
+
+class hscommon.gui.table.Row(table)
+

Represents a row in a Table.

+

It holds multiple values to be represented through columns. It’s its role to prepare data +fetched from model instances into ready-to-present-in-a-table fashion. You will do this in +load().

+

When you do this, you’ll put the result into arbitrary attributes, which will later be fetched +by your table for presentation to the user.

+

You can organize your attributes in whatever way you want, but there’s a convention you can +follow if you want to minimize subclassing and use default behavior:

+
    +
  1. Attribute name = column name. If your attribute is foobar, whenever we refer to +column_name, you refer to that attribute with the column name foobar.
  2. +
  3. Public attributes are for formatted value, that is, user readable strings.
  4. +
  5. Underscore prefix is the unformatted (computable) value. For example, you could have +_foobar at 42 and foobar at "42 seconds" (what you present to the user).
  6. +
  7. Unformatted values are used for sorting.
  8. +
  9. If your column name is a python keyword, add an underscore suffix (from_).
  10. +
+

Of course, this is only default behavior. This can be overriden.

+
+
+can_edit()
+

(Virtual) Whether the whole row can be edited.

+

By default, always returns True. This is for the whole row. For individual cells, it’s +can_edit_cell().

+
+ +
+
+can_edit_cell(column_name)
+

Returns whether cell for column column_name can be edited.

+

By the default, the check is done in many steps:

+
    +
  1. We check whether the whole row can be edited with can_edit(). If it can’t, the cell +can’t either.
  2. +
  3. If the column doesn’t exist as an attribute, we can’t edit.
  4. +
  5. If we have an attribute can_edit_<column_name>, return that.
  6. +
  7. Check if our attribute is a property. If it’s not, it’s not editable.
  8. +
  9. If our attribute is in fact a property, check whether the property is “settable” (has a +fset method). The cell is editable only if the property is “settable”.
  10. +
+
+ +
+
+get_cell_value(attrname)
+

Get cell value for attrname.

+

By default, does a simple getattr(), but it is used to allow subclasses to have +alternative value storage mechanisms.

+
+ +
+
+load()
+

(Virtual/Required) Loads up values from the model to be presented in the table.

+

Usually, our model instances contain values that are not quite ready for display. If you +have number formatting, display calculations and other whatnots to perform, you do it here +and then you put the result in an arbitrary attribute of the row.

+
+ +
+
+save()
+

(Virtual/Required) Saves user edits into your model.

+

If your table is editable, this is called when the user commits his changes. Usually, these +are typed up stuff, or selected indexes. You have to do proper parsing and reference +linking, and save that stuff into your model.

+
+ +
+
+set_cell_value(attrname, value)
+

Set cell value to value for attrname.

+

By default, does a simple setattr(), but it is used to allow subclasses to have +alternative value storage mechanisms.

+
+ +
+
+sort_key_for_column(column_name)
+

(Virtual) Return the value that is to be used to sort by column column_name.

+

By default, looks for an attribute with the same name as column_name, but with an +underscore prefix (“unformatted value”). If there’s none, tries without the underscore. If +there’s none, raises AttributeError.

+
+ +
+ +
+
+class hscommon.gui.table.GUITable
+

Cross-toolkit GUI-enabled table view.

+

Represents a UI element presenting the user with a sortable, selectable, possibly editable, +table view.

+

Behaves like the Table which it subclasses, but is more focused on being the presenter +of some model data to its GUIObject.view. There’s a refresh() +mechanism which ensures fresh data while preserving sorting order and selection. There’s also an +editing mechanism which tracks whether (and which) row is being edited (or added) and +save/cancel edits when appropriate.

+

Subclasses Table and GUIObject. Expected view: +GUITableView.

+
+
+_do_add()
+

(Virtual) Creates a new row, adds it in the table.

+

Returns (row, insert_index).

+
+ +
+
+_do_delete()
+

(Virtual) Delete the selected rows.

+
+ +
+
+_fill()
+

(Virtual/Required) Fills the table with all the rows that this table is supposed to have.

+

Called by refresh(). Does nothing by default.

+
+ +
+
+_is_edited_new()
+

(Virtual) Returns whether the currently edited row should be considered “new”.

+

This is used in cancel_edits() to know whether the cancellation of the edit means a +revert of the row’s value or the removal of the row.

+

By default, always false.

+
+ +
+
+_restore_selection(previous_selection)
+

(Virtual) Restores row selection after a contents-changing operation.

+

Before each contents changing operation, we store our previously selected indexes because in +many cases, such as in refresh(), our selection will be lost. After the operation is +over, we call this method with our previously selected indexes (in previous_selection).

+

The default behavior is (if we indeed have an empty selected_indexes) to re-select +previous_selection. If it was empty, we select the last row of the table.

+

This behavior can, of course, be overriden.

+
+ +
+
+add()
+

Add a new row in edit mode.

+

Requires do_add() to be implemented. The newly added row will be selected and in edit +mode.

+
+ +
+
+can_edit_cell(column_name, row_index)
+

Returns whether the cell at row_index and column_name can be edited.

+

A row is, by default, editable as soon as it has an attr with the same name as column. +If Row.can_edit() returns False, the row is not editable at all. You can set +editability of rows at the attribute level with can_edit_* properties.

+

Mostly just a shortcut to Row.can_edit_cell().

+
+ +
+
+cancel_edits()
+

Cancels the current edit operation.

+

If there’s an edited row, it will be re-initialized (with Row.load()).

+
+ +
+
+delete()
+

Delete the currently selected rows.

+

Requires _do_delete() for this to have any effect on the model. Cancels editing if +relevant.

+
+ +
+
+refresh(refresh_view=True)
+

Empty the table and re-create its rows.

+

_fill() is called after we emptied the table to create our rows. Previous sort order +will be preserved, regardless of the order in which the rows were filled. If there was any +edit operation taking place, it’s cancelled.

+ +++ + + + +
Parameters:refresh_view (bool) – Whether we tell our view to refresh after our refill operation. +Most of the time, it’s what we want, but there’s some cases where +we don’t.
+
+ +
+
+save_edits()
+

Commit user edits to the model.

+

This is done by calling Row.save().

+
+ +
+
+sort_by(column_name, desc=False)
+

Sort table by column_name.

+

Overrides Table.sort_by(). After having performed sorting, calls +_update_selection() to give you the chance, +if appropriate, to update your selected indexes according to, maybe, the selection that you +have in your model.

+

Then, we refresh our view.

+
+ +
+
+edited = None
+

The row being currently edited by the user. None if no edit is taking place.

+
+ +
+ +
+
+class hscommon.gui.table.GUITableView
+

Expected interface for GUITable’s view.

+

Not actually used in the code. For documentation purposes only.

+

Our view, some kind of table view, is expected to sync with the table’s contents by +appropriately behave to all callbacks in this interface.

+

When in edit mode, the content types by the user is expected to be sent as soon as possible +to the Row.

+

Whenever the user changes the selection, we expect the view to call Table.select().

+
+
+refresh()
+

Refreshes the contents of the table widget.

+

Ensures that the contents of the table widget is synced with the model. This includes +selection.

+
+ +
+
+start_editing()
+

Start editing the currently selected row.

+

Begin whatever inline editing support that the view supports.

+
+ +
+
+stop_editing()
+

Stop editing if there’s an inline editing in effect.

+

There’s no “aborting” implied in this call, so it’s appropriate to send whatever the user +has typed and might not have been sent down to the Row yet. After you’ve done that, +stop the editing mechanism.

+
+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/gui/text_field.html b/help/en/developer/hscommon/gui/text_field.html new file mode 100644 index 00000000..6bc78ad0 --- /dev/null +++ b/help/en/developer/hscommon/gui/text_field.html @@ -0,0 +1,160 @@ + + + + + + + + hscommon.gui.text_field — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.gui.text_field

+ ++++ + + + + + + + + +
TextField()Cross-toolkit text field.
TextFieldViewExpected interface for TextField’s view.
+
+
+class hscommon.gui.text_field.TextField
+

Cross-toolkit text field.

+

Represents a UI element allowing the user to input a text value. Its main attribute is +text which acts as the store of the said value.

+

When our model value isn’t a string, we have a built-in parsing/formatting mechanism allowing +us to directly retrieve/set our non-string value through value.

+

Subclasses GUIObject. Expected view: TextFieldView.

+
+
+_format(value)
+

(Virtual) Formats value to put into text.

+

Returns the formatted version of value. Called whenever value changes.

+
+ +
+
+_parse(text)
+

(Virtual) Parses text to put into value.

+

Returns the parsed version of text. Called whenever text changes.

+
+ +
+
+_update(newvalue)
+

(Virtual) Called whenever we have a new value.

+

Whenever our text/value store changes to a new value (different from the old one), this +method is called. By default, it does nothing but you can override it if you want.

+
+ +
+
+_view_updated()
+

(Virtual) Called after view has been set.

+

Doing nothing by default, this method is called after view has been set (it isn’t +called when it’s unset, however). Use this for initialization code that requires a view +(which is often the whole of the initialization code).

+
+ +
+
+refresh()
+

Triggers a view refresh().

+
+ +
+
+text
+

The text that is currently displayed in the widget.

+

str. get/set.

+

This property can be set. When it is, refresh() is called and the view is synced with +our value. Always in sync with value.

+
+ +
+
+value
+

The “parsed” representation of text.

+

arbitrary type. get/set.

+

By default, it’s a mirror of text, but a subclass can override _parse() and +_format() to have anything else. Always in sync with text.

+
+ +
+ +
+
+class hscommon.gui.text_field.TextFieldView
+

Expected interface for TextField’s view.

+

Not actually used in the code. For documentation purposes only.

+

Our view is expected to sync with TextField.text “both ways”, that is, update the +model’s text when the user types something, but also update the text field when refresh() +is called.

+
+
+refresh()
+

Refreshes the contents of the input widget.

+

Ensures that the contents of the input widget is actually TextField.text.

+
+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/gui/tree.html b/help/en/developer/hscommon/gui/tree.html new file mode 100644 index 00000000..d6df3b4e --- /dev/null +++ b/help/en/developer/hscommon/gui/tree.html @@ -0,0 +1,260 @@ + + + + + + + + hscommon.gui.tree — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.gui.tree

+ ++++ + + + + + + + + +
Tree()Cross-toolkit GUI-enabled tree view.
Node(name)Pretty bland node implementation to be used in a Tree.
+
+
+class hscommon.gui.tree.Tree
+

Cross-toolkit GUI-enabled tree view.

+

This class is a bit too thin to be used as a tree view controller out of the box and HS apps +that subclasses it each add quite a bit of logic to it to make it workable. Making this more +usable out of the box is a work in progress.

+

This class is here (in addition to being a Node) mostly to handle selection.

+

Subclasses Node (it is the root node of all its children) and GUIObject.

+
+
+_select_nodes(nodes)
+

(Virtual) Customize node selection behavior.

+

By default, simply set _selected_nodes.

+
+ +
+
+_view_updated()
+

(Virtual) Called after view has been set.

+

Doing nothing by default, this method is called after view has been set (it isn’t +called when it’s unset, however). Use this for initialization code that requires a view +(which is often the whole of the initialization code).

+
+ +
+
+clear()
+

Clears the node of all its children.

+
+ +
+
+_selected_nodes = None
+

Where we store selected nodes (as a list of Node)

+
+ +
+
+selected_node
+

Currently selected node.

+

:class:`Node`. get/set.

+

First of selected_nodes. None if empty.

+
+ +
+
+selected_nodes
+

List of selected nodes in the tree.

+

List of :class:`Node`. get/set.

+

We use nodes instead of indexes to store selection because it’s simpler when it’s time to +manage selection of multiple node levels.

+
+ +
+
+selected_path
+

Currently selected path.

+

:attr:`Node.path`. get/set.

+

First of selected_paths. None if empty.

+
+ +
+
+selected_paths
+

List of selected paths in the tree.

+

List of :attr:`Node.path`. get/set

+

Computed from selected_nodes.

+
+ +
+ +
+
+class hscommon.gui.tree.Node(name)
+

Pretty bland node implementation to be used in a Tree.

+

It has a parent, behaves like a list, its content being its children. Link integrity +is somewhat enforced (adding a child to a node will set the child’s parent, but that’s +pretty much as far as we go, integrity-wise. Nodes don’t tend to move around much in a GUI +tree). We don’t even check for infinite node loops. Don’t play around these grounds too much.

+

Nodes are designed to be subclassed and given meaningful attributes (those you’ll want to +display in your tree view), but they all have a name, which is given on initialization.

+
+
+append(node)
+

S.append(value) – append value to the end of the sequence

+
+ +
+
+clear()
+

Clears the node of all its children.

+
+ +
+
+find(predicate, include_self=True)
+

Return the first child to match predicate.

+

See findall().

+
+ +
+
+findall(predicate, include_self=True)
+

Yield all children matching predicate.

+ +++ + + + +
Parameters:
    +
  • predicatef(node) --> bool
  • +
  • include_self – Whether we can return self or we return only children.
  • +
+
+
+ +
+
+get_node(index_path)
+

Returns the node at index_path.

+ +++ + + + +
Parameters:index_path – a list of int indexes leading to our node. See path.
+
+ +
+
+get_path(target_node)
+

Returns the path of target_node.

+

If target_node is None, returns None.

+
+ +
+
+insert(index, node)
+

S.insert(index, value) – insert value before index

+
+ +
+
+children_count
+

Same as len(self).

+
+ +
+
+name
+

Name for the node, supplied on init.

+
+ +
+
+parent
+

Parent of the node.

+

If None, we have a root node.

+
+ +
+
+path
+

A list of node indexes leading from the root node to self.

+

The path of a node is always related to its root. It’s the sequences of index that +we have to take to get to our node, starting from the root. For example, if +node.path == [1, 2, 3, 4], it means that node.root[1][2][3][4] is node.

+
+ +
+
+root
+

Root node of current node.

+

To get it, we recursively follow our parent chain until we have None.

+
+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/index.html b/help/en/developer/hscommon/index.html new file mode 100644 index 00000000..3e37011f --- /dev/null +++ b/help/en/developer/hscommon/index.html @@ -0,0 +1,83 @@ + + + + + + + + hscommon — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/jobprogress/job.html b/help/en/developer/hscommon/jobprogress/job.html new file mode 100644 index 00000000..48473490 --- /dev/null +++ b/help/en/developer/hscommon/jobprogress/job.html @@ -0,0 +1,147 @@ + + + + + + + + hscommon.jobprogress.job — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.jobprogress.job

+ ++++ + + + + + + + + +
Job(job_proportions, callback)Manages a job’s progression and return it’s progression through a callback.
NullJob(*args, **kwargs)
+
+
+class hscommon.jobprogress.job.Job(job_proportions, callback)
+

Manages a job’s progression and return it’s progression through a callback.

+

Note that this class is not foolproof. For example, you could call +start_subjob, and then call add_progress from the parent job, and nothing +would stop you from doing it. However, it would mess your progression +because it is the sub job that is supposed to drive the progression. +Another example would be to start a subjob, then start another, and call +add_progress from the old subjob. Once again, it would mess your progression. +There are no stops because it would remove the lightweight aspect of the +class (A Job would need to have a Parent instead of just a callback, +and the parent could be None. A lot of checks for nothing.). +Another one is that nothing stops you from calling add_progress right after +SkipJob.

+
+
+_do_update(desc)
+

Calls the callback function with a % progress as a parameter.

+

The parameter is a int in the 0-100 range.

+
+ +
+
+_subjob_callback(progress, desc='')
+

This is the callback passed to children jobs.

+
+ +
+
+iter_with_progress(iterable, desc_format=None, every=1, count=None)
+

Iterate through iterable while automatically adding progress.

+

WARNING: We need our iterable’s length. If iterable is not a sequence (that is, +something we can call len() on), you have to specify a count through the count +argument. If count is None, len(iterable) is used.

+
+ +
+
+set_progress(progress, desc='')
+

Sets the progress of the current job to ‘progress’, and call the +callback

+
+ +
+
+start_job(max_progress=100, desc='')
+

Begin work on the next job. You must not call start_job more than +‘jobcount’ (in __init__) times. +‘max’ is the job units you are to perform. +‘desc’ is the description of the job.

+
+ +
+
+start_subjob(job_proportions, desc='')
+

Starts a sub job. Use this when you want to split a job into +multiple smaller jobs. Pretty handy when starting a process where you +know how many subjobs you will have, but don’t know the work unit count +for every of them. +returns the Job object

+
+ +
+ +
+
+class hscommon.jobprogress.job.NullJob(*args, **kwargs)
+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/jobprogress/performer.html b/help/en/developer/hscommon/jobprogress/performer.html new file mode 100644 index 00000000..421dade2 --- /dev/null +++ b/help/en/developer/hscommon/jobprogress/performer.html @@ -0,0 +1,92 @@ + + + + + + + + hscommon.jobprogress.performer — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.jobprogress.performer

+ ++++ + + + + + +
ThreadedJobPerformerRun threaded jobs and track progress.
+
+
+class hscommon.jobprogress.performer.ThreadedJobPerformer
+

Run threaded jobs and track progress.

+

To run a threaded job, first create a job with _create_job(), then call _run_threaded(), with +your work function as a parameter.

+

Example:

+

j = self._create_job() +self._run_threaded(self.some_work_func, (arg1, arg2, j))

+
+
+reraise_if_error()
+

Reraises the error that happened in the thread if any.

+

Call this after the caller of run_threaded detected that self._job_running returned to False

+
+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/jobprogress/qt.html b/help/en/developer/hscommon/jobprogress/qt.html new file mode 100644 index 00000000..e7b86211 --- /dev/null +++ b/help/en/developer/hscommon/jobprogress/qt.html @@ -0,0 +1,79 @@ + + + + + + + + hscommon.jobprogress.qt — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.jobprogress.qt

+ ++++ + + + + + +
Progress(parent)
+
+
+class hscommon.jobprogress.qt.Progress(parent)
+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/notify.html b/help/en/developer/hscommon/notify.html new file mode 100644 index 00000000..942e4706 --- /dev/null +++ b/help/en/developer/hscommon/notify.html @@ -0,0 +1,113 @@ + + + + + + + + hscommon.notify — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.notify

+

Very simple inter-object notification system.

+

This module is a brain-dead simple notification system involving a Broadcaster and a +Listener. A listener can only listen to one broadcaster. A broadcaster can have multiple +listeners. If the listener is connected, whenever the broadcaster calls notify(), +the method with the same name as the broadcasted message is called on the listener.

+
+
+class hscommon.notify.Broadcaster
+

Broadcasts messages that are received by all listeners.

+
+
+notify(msg)
+

Notify all connected listeners of msg.

+

That means that each listeners will have their method with the same name as msg called.

+
+ +
+ +
+
+class hscommon.notify.Listener(broadcaster)
+

A listener is initialized with the broadcaster it’s going to listen to. Initially, it is not connected.

+
+
+bind_messages(messages, func)
+

Binds multiple message to the same function.

+

Often, we perform the same thing on multiple messages. Instead of having the same function +repeated again and agin in our class, we can use this method to bind multiple messages to +the same function.

+
+ +
+
+connect()
+

Connects the listener to its broadcaster.

+
+ +
+
+disconnect()
+

Disconnects the listener from its broadcaster.

+
+ +
+ +
+
+class hscommon.notify.Repeater(broadcaster)
+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/path.html b/help/en/developer/hscommon/path.html new file mode 100644 index 00000000..e48f78ba --- /dev/null +++ b/help/en/developer/hscommon/path.html @@ -0,0 +1,118 @@ + + + + + + + + hscommon.path — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.path

+
+
+class hscommon.path.Path
+

A handy class to work with paths.

+

We subclass tuple, each element of the tuple represents an element of the path.

+
    +
  • Path('/foo/bar/baz')[1] –> 'bar'
  • +
  • Path('/foo/bar/baz')[1:2] –> Path('bar/baz')
  • +
  • Path('/foo/bar')['baz'] –> Path('/foo/bar/baz')
  • +
  • str(Path('/foo/bar/baz')) –> '/foo/bar/baz'
  • +
+
+
+is_parent_of(other)
+

Whether other is a subpath of self.

+

Almost the same as other in self, but it’s a bit more self-explicative and when +other == self, returns False.

+
+ +
+
+parent()
+

Returns the parent path.

+

Path('/foo/bar/baz').parent() –> Path('/foo/bar')

+
+ +
+
+name
+

Last element of the path (filename), with extension.

+

Path('/foo/bar/baz').name –> 'baz'

+
+ +
+ +
+
+hscommon.path.log_io_error(func)
+

Catches OSError, IOError and WindowsError and log them

+
+ +
+
+hscommon.path.pathify(f)
+

Ensure that every annotated Path arguments are actually paths.

+

When a function is decorated with @pathify, every argument with annotated as Path will be +converted to a Path if it wasn’t already. Example:

+
@pathify
+def foo(path: Path, otherarg):
+    return path.listdir()
+
+
+

Calling foo('/bar', 0) will convert '/bar' to Path('/bar').

+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/hscommon/util.html b/help/en/developer/hscommon/util.html new file mode 100644 index 00000000..dc81180e --- /dev/null +++ b/help/en/developer/hscommon/util.html @@ -0,0 +1,289 @@ + + + + + + + + hscommon.util — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

hscommon.util

+
+
+class hscommon.util.FileOrPath(file_or_path, mode='rb')
+

Does the same as open_if_filename(), but it can be used with a with statement.

+

Example:

+
with FileOrPath(infile):
+    dostuff()
+
+
+
+ +
+
+hscommon.util.RE_INVALID_XML_SUB()
+

Return the string obtained by replacing the leftmost non-overlapping occurrences of pattern in string by the replacement repl.

+
+ +
+
+hscommon.util.allsame(iterable)
+

Returns whether all elements of ‘iterable’ are the same.

+
+ +
+
+hscommon.util.dedupe(iterable)
+

Returns a list of elements in iterable with all dupes removed.

+

The order of the elements is preserved.

+
+ +
+
+hscommon.util.delete_files_with_pattern(folder_path, pattern, recursive=True)
+

Delete all files (or folders) in folder_path that match the glob pattern.

+
+ +
+
+hscommon.util.delete_if_empty(path: hscommon.path.Path, files_to_delete=[])
+

Deletes the directory at ‘path’ if it is empty or if it only contains files_to_delete.

+
+ +
+
+hscommon.util.ensure_file(path)
+

Create path as an empty file if it doesn’t exist.

+
+ +
+
+hscommon.util.ensure_folder(path)
+

Create path as a folder if it doesn’t exist.

+
+ +
+
+hscommon.util.escape(s, to_escape, escape_with='\\')
+

Returns s with characters in to_escape all prepended with escape_with.

+
+ +
+
+hscommon.util.extract(predicate, iterable)
+

Separates the wheat from the shaft (predicate defines what’s the wheat), and returns both.

+
+ +
+
+hscommon.util.find_in_path(name, paths=None)
+

Search for name in all directories of paths and return the absolute path of the first +occurrence. If paths is None, $PATH is used.

+
+ +
+
+hscommon.util.first(iterable)
+

Returns the first item of iterable.

+
+ +
+
+hscommon.util.flatten(iterables, start_with=None)
+

Takes a list of lists iterables and returns a list containing elements of every list.

+

If start_with is not None, the result will start with start_with items, exactly as +if start_with would be the first item of lists.

+
+ +
+
+hscommon.util.format_size(size, decimal=0, forcepower=-1, showdesc=True)
+

Transform a byte count in a formatted string (KB, MB etc..).

+

size is the number of bytes to format. +decimal is the number digits after the dot. +forcepower is the desired suffix. 0 is B, 1 is KB, 2 is MB etc.. if kept at -1, the suffix +will be automatically chosen (so the resulting number is always below 1024). +if showdesc is True, the suffix will be shown after the number. +Usage example:

+
>>> format_size(1234, decimal=2, showdesc=True)
+'1.21 KB'
+
+
+
+ +
+
+hscommon.util.format_time(seconds, with_hours=True)
+

Transforms seconds in a hh:mm:ss string.

+

If with_hours if false, the format is mm:ss.

+
+ +
+
+hscommon.util.format_time_decimal(seconds)
+

Transforms seconds in a strings like ‘3.4 minutes’.

+
+ +
+
+hscommon.util.get_file_ext(filename)
+

Returns the lowercase extension part of filename, without the dot.

+
+ +
+
+hscommon.util.iterconsume(seq, reverse=True)
+

Iterate over seq and pops yielded objects.

+

Because we use the pop() method, we reverse seq before proceeding. If you don’t need +to do that, set reverse to False.

+

This is useful in tight memory situation where you are looping over a sequence of objects that +are going to be discarded afterwards. If you’re creating other objects during that iteration +you might want to use this to avoid MemoryError.

+
+ +
+
+hscommon.util.iterdaterange(start, end)
+

Yields every day between start and end.

+
+ +
+
+hscommon.util.minmax(value, min_value, max_value)
+

Returns value or one of the min/max bounds if value is not between them.

+
+ +
+
+hscommon.util.modified_after(first_path: hscommon.path.Path, second_path: hscommon.path.Path)
+

Returns True if first_path’s mtime is higher than second_path’s mtime.

+

If one of the files doesn’t exist or is None, it is considered “never modified”.

+
+ +
+
+hscommon.util.multi_replace(s, replace_from, replace_to='')
+

A function like str.replace() with multiple replacements.

+

replace_from is a list of things you want to replace. Ex: [‘a’,’bc’,’d’] +replace_to is a list of what you want to replace to. +If replace_to is a list and has the same length as replace_from, replace_from +items will be translated to corresponding replace_to. A replace_to list must +have the same length as replace_from +If replace_to is a string, all replace_from occurence will be replaced +by that string. +replace_from can also be a str. If it is, every char in it will be translated +as if replace_from would be a list of chars. If replace_to is a str and has +the same length as replace_from, it will be transformed into a list.

+
+ +
+
+hscommon.util.nonone(value, replace_value)
+

Returns value if value is not None. Returns replace_value otherwise.

+
+ +
+
+hscommon.util.open_if_filename(infile, mode='rb')
+

If infile is a string, it opens and returns it. If it’s already a file object, it simply returns it.

+

This function returns (file, should_close_flag). The should_close_flag is True is a file has +effectively been opened (if we already pass a file object, we assume that the responsibility for +closing the file has already been taken). Example usage:

+
fp, shouldclose = open_if_filename(infile)
+dostuff()
+if shouldclose:
+    fp.close()
+
+
+
+ +
+
+hscommon.util.pluralize(number, word, decimals=0, plural_word=None)
+

Returns a pluralized string with number in front of word.

+

Adds a ‘s’ to s if number > 1. +number: The number to go in front of s +word: The word to go after number +decimals: The number of digits after the dot +plural_word: If the plural rule for word is more complex than adding a ‘s’, specify a plural

+
+ +
+
+hscommon.util.rem_file_ext(filename)
+

Returns the filename without extension.

+
+ +
+
+hscommon.util.stripfalse(seq)
+

Returns a sequence with all false elements stripped out of seq.

+
+ +
+
+hscommon.util.trailiter(iterable, skipfirst=False)
+

Yields (prev_element, element), starting with (None, first_element).

+

If skipfirst is True, there will be no (None, item1) element and we’ll start +directly with (item1, item2).

+
+ +
+
+hscommon.util.tryint(value, default=0)
+

Tries to convert value to in int and returns default if it fails.

+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/developer/index.html b/help/en/developer/index.html new file mode 100644 index 00000000..7a66cdb7 --- /dev/null +++ b/help/en/developer/index.html @@ -0,0 +1,149 @@ + + + + + + + + Developer Guide — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

Developer Guide

+

When looking at a non-trivial codebase for the first time, it’s very difficult to understand +anything of it until you get the “Big Picture”. This page is meant to, hopefully, make you get +dupeGuru’s big picture.

+
+

Branches and tags

+

The git repo has one main branch, master. It represents the latest “stable development commit”, +that is, the latest commit that doesn’t include in-progress features. This branch should always +be buildable, tox should always run without errors on it.

+

When a feature/bugfix has an atomicity of a single commit, it’s alright to commit right into +master. However, if a feature/bugfix needs more than a commit, it should live in a separate +topic branch until it’s ready.

+

Every release is tagged with the version number. For example, there’s a 2.8.2 tag for the +v2.8.2 release.

+
+
+

Model/View/Controller… nope!

+

dupeGuru’s codebase has quite a few design flaws. The Model, View and Controller roles are filled by +different classes, scattered around. If you’re aware of that, it might help you to understand what +the heck is going on.

+

The central piece of dupeGuru is core.app.DupeGuru. It’s the only +interface to the python’s code for the GUI code. A duplicate scan is started with +core.app.DupeGuru.start_scanning(), directories are added through +core.app.DupeGuru.add_directory(), etc..

+

A lot of functionalities of the App are implemented in the platform-specific subclasses of +core.app.DupeGuru, like DupeGuru in cocoa/inter/app.py, or the DupeGuru class +in qt/base/app.py. For example, when performing “Remove Selected From Results”, +RemoveSelected() on the cocoa side, and remove_duplicates() on the PyQt side, are +respectively called to perform the thing.

+
+
+

Jobs

+

A lot of operations in dupeGuru take a significant amount of time. This is why there’s a generalized +threaded job mechanism built-in DupeGuru. First, DupeGuru has +a progress member which is an instance of +ThreadedJobPerformer. It lets the GUI code know of the progress +of the current threaded job. When DupeGuru needs to start a job, it calls +_start_job() and the platform specific subclass deals with the details of starting the job.

+
+
+

Core principles

+

The core of the duplicate matching takes place (for SE and ME, not PE) in core.engine. +There’s core.engine.getmatches() which take a list of core.fs.File instances and +return a list of (firstfile, secondfile, match_percentage) matches. Then, there’s +core.engine.get_groups() which takes a list of matches and returns a list of +Group instances (a Group is basically a list of File matching +together).

+

When a scan is over, the final result (the list of groups from get_groups()) is placed into +core.app.DupeGuru.results, which is a core.results.Results instance. The +Results instance is where all the dupe marking, sorting, removing, power marking, etc. +takes place.

+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/faq.html b/help/en/faq.html new file mode 100644 index 00000000..09a789b0 --- /dev/null +++ b/help/en/faq.html @@ -0,0 +1,253 @@ + + + + + + + + Frequently Asked Questions — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

Frequently Asked Questions

+ +
+

What is dupeGuru?

+

dupeGuru is a tool to find duplicate files on your computer. It has three operational modes: +Standard, Music and Picture. Each mode has its own specialized preferences.

+

Each mode has multiple scan types, such as filename, contents, tags. Some scan types feature +advanced fuzzy matching algorithm, allowing you to find duplicates that other more rigid duplicate +scanners can’t.

+
+
+

What makes it special?

+

It’s mostly about customizability. There’s a lot of scanning options that allow you to get the +type of results you’re really looking for.

+
+
+

How safe is it to use dupeGuru?

+

Very safe. dupeGuru has been designed to make sure you don’t delete files you didn’t mean to delete. +First, there is the reference folder system that lets you define folders where you absolutely +don’t want dupeGuru to let you delete files there, and then there is the group reference system +that makes sure that you will always keep at least one member of the duplicate group.

+
+
+

How can I report a bug a suggest a feature?

+

dupeGuru is hosted on Github and it’s also where issues are tracked. The best way to report a +bug or suggest a feature is to sign up on Github and open an issue.

+
+
+

The mark box of a file I want to delete is disabled. What must I do?

+

You cannot mark the reference (The first file) of a duplicate group. However, what you can do is to +promote a duplicate file to reference. Thus, if a file you want to mark is reference, select a +duplicate file in the group that you want to promote to reference, and click on +Actions–>Make Selected into Reference. If the reference file is from a reference folder +(filename written in blue letters), you cannot remove it from the reference position.

+
+
+

I have a folder from which I really don’t want to delete files.

+

If you want to be sure that dupeGuru will never delete file from a particular folder, make sure to +set its state to Reference at Folder Selection.

+
+
+

What is this ‘(X discarded)’ notice in the status bar?

+

In some cases, some matches are not included in the final results for security reasons. Let me use +an example. We have 3 file: A, B and C. We scan them using a low filter hardness. The scanner +determines that A matches with B, A matches with C, but B does not match with C. Here, dupeGuru +has kind of a problem. It cannot create a duplicate group with A, B and C in it because not all +files in the group would match together. It could create 2 groups: one A-B group and then one A-C +group, but it will not, for security reasons. Lets think about it: If B doesn’t match with C, it +probably means that either B, C or both are not actually duplicates. If there would be 2 groups (A-B +and A-C), you would end up delete both B and C. And if one of them is not a duplicate, that is +really not what you want to do, right? So what dupeGuru does in a case like this is to discard the +A-C match (and adds a notice in the status bar). Thus, if you delete B and re-run a scan, you will +have a A-C match in your next results.

+
+
+

I want to mark all files from a specific folder. What can I do?

+

Enable the Dupes Only mode and click on the Folder column to sort your duplicates +by folder. It will then be easy for you to select all duplicates from the same folder, and then +press Space to mark all selected duplicates.

+
+
+

I want to remove all files that are more than 300 KB away from their reference file. What can I do?

+
    +
  • Enable the Dupes Only mode.
  • +
  • Enable the Delta Values mode.
  • +
  • Click on the “Size” column to sort the results by size.
  • +
  • Select all duplicates below -300.
  • +
  • Click on Remove Selected from Results.
  • +
  • Select all duplicates over 300.
  • +
  • Click on Remove Selected from Results.
  • +
+
+
+

I want to make my latest modified files reference files. What can I do?

+
    +
  • Enable the Dupes Only mode.
  • +
  • Enable the Delta Values mode.
  • +
  • Click on the “Modification” column to sort the results by modification date.
  • +
  • Click on the “Modification” column again to reverse the sort order.
  • +
  • Select all duplicates over 0.
  • +
  • Click on Make Selected into Reference.
  • +
+
+
+

I want to mark all duplicates containing the word “copy”. How do I do that?

+
    +
  • Type “copy” in the “Filter” field in the top-right corner of the result window.
  • +
  • Click on Mark –> Mark All.
  • +
+
+
+

I want to remove all songs that are more than 3 seconds away from their reference file. What can I do?

+
    +
  • Enable the Dupes Only mode.
  • +
  • Enable the Delta Values mode.
  • +
  • Click on the “Time” column to sort the results by time.
  • +
  • Select all duplicates below -00:03.
  • +
  • Click on Remove Selected from Results.
  • +
  • Select all duplicates over 00:03.
  • +
  • Click on Remove Selected from Results.
  • +
+
+
+

I want to make my highest bitrate songs reference files. What can I do?

+
    +
  • Enable the Dupes Only mode.
  • +
  • Enable the Delta Values mode.
  • +
  • Click on the “Bitrate” column to sort the results by bitrate.
  • +
  • Click on the “Bitrate” column again to reverse the sort order.
  • +
  • Select all duplicates over 0.
  • +
  • Click on Make Selected into Reference.
  • +
+
+
+

I don’t want [live] and [remix] versions of my songs counted as duplicates. How do I do that?

+

If your comparison threshold is low enough, you will probably end up with live and remix +versions of your songs in your results. There’s nothing you can do to prevent that, but there’s +something you can do to easily remove them from your results after the scan: post-scan +filtering. If, for example, you want to remove every song with anything inside square brackets +[]:

+
    +
  • Type “[*]” in the “Filter” field in the top-right corner of the result window.
  • +
  • Click on Mark –> Mark All.
  • +
  • Click on Actions –> Remove Selected from Results.
  • +
+
+
+

The “Filter Hardness” slider in the preferences won’t move!

+

This slider is only relevant for scan types that support “fuzziness”. Many scan types, such as the +“Contents” type, only support exact matches. When these types are selected, the slider is disabled.

+

On some OS, the fact that it’s disabled is harder to see than on others, but if you can’t move the +slider, it means that this preference is irrelevant in your current scan type.

+
+
+

I’ve tried to send my duplicates to Trash, but dupeGuru is telling me it can’t do it. Why? What can I do?

+

Most of the time, the reason why dupeGuru can’t send files to Trash is because of file permissions. +You need write permissions on files you want to send to Trash.

+

If dupeGuru still gives you troubles after fixing your permissions, try enabling the “Directly +delete files” option that is offered to you when you activate Send to Trash. This will not send +files to the Trash, but delete them immediately. In some cases, for example on network storage +(NAS), this has been known to work when normal deletion didn’t.

+

If this fail, HS forums might be of some help.

+
+
+

Why is Picture mode’s contents scan so slow?

+

This scanning method is very different from methods. It can detect duplicate photos even if they +are not exactly the same. This very cool capability has a cost: time. Every picture has to be +individually and fuzzily matched to all others, and this takes a lot of CPU power.

+

If all you need to find is exact duplicates, just use the standard mode of dupeGuru with the +Contents scan method. If your photos have EXIF tags, you can also try the “EXIF” scan method which +is much faster.

+
+
+

Where are user files located?

+

For some reason, you’d like to remove or edit dupeGuru’s user files (debug logs, caches, etc.). +Where they’re located depends on your platform:

+
    +
  • Linux: ~/.local/share/data/Hardcoded Software/dupeGuru
  • +
  • Mac OS X: ~/Library/Application Support/dupeGuru
  • +
+

Preferences are stored elsewhere:

+
    +
  • Linux: ~/.config/Hardcoded Software/dupeGuru.conf
  • +
  • Mac OS X: In the built-in defaults system, as com.hardcoded-software.dupeguru
  • +
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/folders.html b/help/en/folders.html new file mode 100644 index 00000000..f1bfdf0d --- /dev/null +++ b/help/en/folders.html @@ -0,0 +1,125 @@ + + + + + + + + Folder Selection — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

Folder Selection

+

The first window you see when you launch dupeGuru is the folder selection window. This windows +contains the basic input dupeGuru needs to start a scan:

+
    +
  • An Application Mode selection
  • +
  • A Scan Type selection
  • +
  • Folders to scan
  • +
+
+

Application Mode

+

dupeGuru had three main modes: Standard, Music and Picture.

+

Standard is for any type of files. This makes this mode the most polyvalent, but it lacks +specialized features other modes have.

+

Music mode scans only music files, but it supports tags comparison and its results window has many +audio-related informational columns.

+

Picture mode scans only pictures, but its contents scan type is a powerful fuzzy matcher that can +find pictures that are similar without being exactly the same.

+

Choosing an application mode not only changes available scan types in the selector below, but also +changes available options in the preferences panel. Thus, if you want to fine tune your scan, be +sure to open the preferences panel after you’ve selected the application mode.

+
+
+

Scan Type

+

This selector determines the type of the scan we’ll do. See The scanning process for details about scan +types.

+
+
+

Folder List

+

To add a folder, click on the + button. If you added folder before, a popup +menu with a list of recent folders you added will pop. You can click on one of +them to add it directly to your list. If you click on the first item of the +popup menu, Add New Folder…, you will be prompted for a folder to add. If +you never added a folder, no menu will pop and you will directly be prompted +for a new folder to add.

+

An alternate way to add folders to the list is to drag them in the list.

+

To remove a folder, select the folder to remove and click on -. If a subfolder is selected when +you click the button, the selected folder will be set to excluded state (see below) instead of +being removed.

+
+
+

Folder states

+

Every folder can be in one of these 3 states:

+
+
Normal:
+
Duplicates found in this folder can be deleted.
+
Reference:
+
Duplicates found in this folder cannot be deleted. Files from this folder can +only end up in reference position in the dupe group. If more than one file from reference +folders end up in the same dupe group, only one will be kept. The others will be removed from +the group.
+
Excluded:
+
Files in this directory will not be included in the scan.
+
+

The default state of a folder is, of course, Normal. You can use Reference state for a +folder if you want to be sure that you won’t delete any file from it.

+

When you set the state of a directory, all subfolders of this folder automatically inherit this +state unless you explicitly set a subfolder’s state.

+
+
+

Scan

+

When you’re ready, click on the Scan button to initiate the scanning process. When it’s done, +you’ll be shown the Results.

+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/genindex.html b/help/en/genindex.html new file mode 100644 index 00000000..689ca35c --- /dev/null +++ b/help/en/genindex.html @@ -0,0 +1,957 @@ + + + + + + + + + Index — dupeGuru 4.0.3 documentation + + + + + + + + + + + + +
+ + + +

Index

+ +
+ _ + | A + | B + | C + | D + | E + | F + | G + | H + | I + | J + | L + | M + | N + | O + | P + | R + | S + | T + | U + | V + | W + +
+

_

+ + + +
+ +

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + + +
+ +

J

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ +

V

+ + + +
+ +

W

+ + + +
+ + + +
+ + + + + \ No newline at end of file diff --git a/help/en/index.html b/help/en/index.html new file mode 100644 index 00000000..188f4fb2 --- /dev/null +++ b/help/en/index.html @@ -0,0 +1,151 @@ + + + + + + + + dupeGuru help — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + +
+ + +
+

dupeGuru help

+

This help document is also available in these languages:

+ +

dupeGuru is a tool to find duplicate files on your computer. It has three +modes, Standard, Music and Picture, with each mode having its own scan types +and little features.

+

Although dupeGuru can easily be used without documentation, reading this file +will help you to master it. If you are looking for guidance for your first +duplicate scan, you can take a look at the Quick Start +section.

+

It is a good idea to keep dupeGuru updated. You can download the latest version on its homepage.

+

Contents:

+
+ +
+
+
+

Indices and tables

+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/objects.inv b/help/en/objects.inv new file mode 100644 index 00000000..3ed624e2 Binary files /dev/null and b/help/en/objects.inv differ diff --git a/help/en/preferences.html b/help/en/preferences.html new file mode 100644 index 00000000..be0b00ec --- /dev/null +++ b/help/en/preferences.html @@ -0,0 +1,128 @@ + + + + + + + + Preferences — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

Preferences

+
+
Tags to scan:
+
When using the Tags scan type, you can select the tags that will be used for comparison.
+
Word weighting:
+
See Word weighting.
+
Match similar words:
+
See Similarity matching.
+
Match pictures of different dimensions:
+
If you check this box, pictures of different dimensions will be allowed in the same +duplicate group.
+
+
+
Filter Hardness:
+
The threshold needed for two files to be considered duplicates. A lower value means more +duplicates. The meaning of the threshold depends on the scanning type (see The scanning process). +Only works for worded and picture blocks +scans.
+
Can mix file kind:
+
If you check this box, duplicate groups are allowed to have files with different extensions. If +you don’t check it, well, they aren’t!
+
Ignore duplicates hardlinking to the same file:
+
If this option is enabled, dupeGuru will verify duplicates to see if they refer to the same +inode. If they do, they will not be considered duplicates. (Only for OS X and Linux)
+
Use regular expressions when filtering:
+
If you check this box, the filtering feature will treat your filter query as a +regular expression. Explaining them is beyond the scope of this document. A good place to +start learning it is regular-expressions.info.
+
Remove empty folders after delete or move:
+
When this option is enabled, folders are deleted after a file is deleted or moved and the folder +is empty.
+
Copy and Move:
+
Determines how the Copy and Move operations (in the Action menu) will behave.
+
+
    +
  • Right in destination: All files will be sent directly in the selected destination, without +trying to recreate the source path at all.
  • +
  • Recreate relative path: The source file’s path will be re-created in the destination folder up +to the root selection in the Directories panel. For example, if you added +/Users/foobar/SomeFolder to your Directories panel and you move +/Users/foobar/SomeFolder/SubFolder/SomeFile.ext to the destination +/Users/foobar/MyDestination, the final destination for the file will be +/Users/foobar/MyDestination/SubFolder (SomeFolder has been trimmed from source’s path in +the final destination.).
  • +
  • Recreate absolute path: The source file’s path will be re-created in the destination folder in +its entirety. For example, if you move /Users/foobar/SomeFolder/SubFolder/SomeFile.ext to the +destination /Users/foobar/MyDestination, the final destination for the file will be +/Users/foobar/MyDestination/Users/foobar/SomeFolder/SubFolder.
  • +
+

In all cases, dupeGuru nicely handles naming conflicts by prepending a number to the destination +filename if the filename already exists in the destination.

+
+
Custom Command:
+
This preference determines the command that will be invoked by the “Invoke Custom Command” +action. You can invoke any external application through this action. This can be useful if, +for example, you have a nice diffing application installed.
+
+

The format of the command is the same as what you would write in the command line, except that there +are 2 placeholders: %d and %r. These placeholders will be replaced by the path of the +selected dupe (%d) and the path of the selected dupe’s reference file (%r).

+

If the path to your executable contains space characters, you should enclose it in “” quotes. You +should also enclose placeholders in quotes because it’s very possible that paths to dupes and refs +will contain spaces. Here’s an example custom command:

+
"C:\Program Files\SuperDiffProg\SuperDiffProg.exe" "%d" "%r"
+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/py-modindex.html b/help/en/py-modindex.html new file mode 100644 index 00000000..cb8beb61 --- /dev/null +++ b/help/en/py-modindex.html @@ -0,0 +1,196 @@ + + + + + + + + Python Module Index — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + +
+ + + +

Python Module Index

+ +
+ c | + h +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ c
+ core +
    + core.app +
    + core.directories +
    + core.engine +
    + core.fs +
    + core.gui +
    + core.gui.deletion_options +
    + core.results +
 
+ h
+ hscommon +
    + hscommon.build +
    + hscommon.conflict +
    + hscommon.desktop +
    + hscommon.gui.base +
    + hscommon.gui.column +
    + hscommon.gui.progress_window +
    + hscommon.gui.selectable_list +
    + hscommon.gui.table +
    + hscommon.gui.text_field +
    + hscommon.gui.tree +
    + hscommon.jobprogress.job +
    + hscommon.jobprogress.performer +
    + hscommon.jobprogress.qt +
    + hscommon.notify +
    + hscommon.path +
    + hscommon.util +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/quick_start.html b/help/en/quick_start.html new file mode 100644 index 00000000..2dc3d158 --- /dev/null +++ b/help/en/quick_start.html @@ -0,0 +1,74 @@ + + + + + + + + Quick Start — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

Quick Start

+

To get you quickly started with dupeGuru, let’s just make a standard scan using default preferences.

+
    +
  • Launch dupeGuru.
  • +
  • Add folders to scan with either drag & drop or the “+” button.
  • +
  • Click on Scan.
  • +
  • Wait until the scan process is over.
  • +
  • Look at every duplicate (The files that are indented) and verify that it is indeed a duplicate to the group’s reference (The file above the duplicate that is not indented and have a disabled mark box).
  • +
  • If a file is a false duplicate, select it and click on Actions–>Remove Selected from Results.
  • +
  • Once you are sure that there is no false duplicate in your results, click on Edit–>Mark All, and then Actions–>Send Marked to Recycle bin.
  • +
+

That is only a basic scan. There are a lot of tweaking you can do to get different results and several methods of examining and modifying your results. To know about them, just read the rest of this help file.

+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/reprioritize.html b/help/en/reprioritize.html new file mode 100644 index 00000000..495f110c --- /dev/null +++ b/help/en/reprioritize.html @@ -0,0 +1,82 @@ + + + + + + + + Re-Prioritizing duplicates — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

Re-Prioritizing duplicates

+

dupeGuru tries to automatically determine which duplicate should go in each group’s reference +position, but sometimes it gets it wrong. In many cases, clever dupe sorting with “Delta Values” +and “Dupes Only” options in addition to the “Make Selected into Reference” action does the trick, +but sometimes, a more powerful option is needed. This is where the Re-Prioritization dialog comes +into play. You can summon it through the “Re-Prioritize Results” item in the “Actions” menu.

+

This dialog allows you to select criteria according to which a reference dupe will be selected in +each dupe group. The list of available criteria is on the left and the list of criteria you’ve +selected is on the right.

+

A criteria is a category followed by an argument. For example, “Size (Highest)” means that the dupe +with the biggest size will win. “Folder (/foo/bar)” means that dupes in this folder will win. To add +a criterion to the rightmost list, first select a category in the combobox, then select a +subargument in the list below, and then click on the right pointing arrow button.

+

The order of the list on the right is important (you can re-order items through drag & drop). When +picking a dupe for reference position, the first criterion is used. If there’s a tie, the second +criterion is used and so on and so on. For example, if your arguments are “Size (Highest)” and then +“Filename (Doesn’t end with a number)”, the reference file that will be picked in a group will be +the biggest file, and if two or more files have the same size, the one that has a filename that +doesn’t end with a number will be used. When all criteria result in ties, the order in which dupes +previously were in the group will be used.

+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/results.html b/help/en/results.html new file mode 100644 index 00000000..0e5a7f1e --- /dev/null +++ b/help/en/results.html @@ -0,0 +1,243 @@ + + + + + + + + Results — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

Results

+ +

When dupeGuru is finished scanning for duplicates, it will show its results in the form of duplicate group list.

+
+

About duplicate groups

+

A duplicate group is a group of files that all match together. Every group has a reference file and one or more duplicate files. The reference file is the first file of the group. Its mark box is disabled. Below it, and indented, are the duplicate files.

+

You can mark duplicate files, but you can never mark the reference file of a group. This is a security measure to prevent dupeGuru from deleting not only duplicate files, but their reference. You sure don’t want that, do you?

+

What determines which files are reference and which files are duplicates is first their folder state. A file from a reference folder will always be reference in a duplicate group. If all files are from a normal folder, the size determine which file will be the reference of a duplicate group. dupeGuru assumes that you always want to keep the biggest file, so the biggest files will take the reference position.

+

You can change the reference file of a group manually. To do so, select the duplicate file you want +to promote to reference, and click on Actions–>Make Selected into Reference.

+
+
+

Reviewing results

+

Although you can just click on Edit–>Mark All and then Actions–>Send Marked to Recycle bin to quickly delete all duplicate files in your results, it is always recommended to review all duplicates before deleting them.

+

To help you reviewing the results, you can bring up the Details panel. This panel shows all the details of the currently selected file as well as its reference’s details. This is very handy to quickly determine if a duplicate really is a duplicate. You can also double-click on a file to open it with its associated application.

+

If you have more false duplicates than true duplicates (If your filter hardness is very low), the best way to proceed would be to review duplicates, mark true duplicates and then click on Actions–>Send Marked to Recycle bin. If you have more true duplicates than false duplicates, you can instead mark all files that are false duplicates, and use Actions–>Remove Marked from Results.

+
+
+

Marking and Selecting

+

A marked duplicate is a duplicate with the little box next to it having a check-mark. A selected duplicate is a duplicate being highlighted. The multiple selection actions can be performed in dupeGuru in the standard way (Shift/Command/Control click). You can toggle all selected duplicates’ mark state by pressing space.

+
+
+

Show Dupes Only

+

When this mode is enabled, the duplicates are shown without their respective reference file. You can select, mark and sort this list, just like in normal mode.

+

The dupeGuru results, when in normal mode, are sorted according to duplicate groups’ reference file. This means that if you want, for example, to mark all duplicates with the “exe” extension, you cannot just sort the results by “Kind” to have all exe duplicates together because a group can be composed of more than one kind of files. That is where Dupes Only mode comes into play. To mark all your “exe” duplicates, you just have to:

+
    +
  • Enable the Dupes Only mode.
  • +
  • Add the “Kind” column with the “Columns” menu.
  • +
  • Click on that “Kind” column to sort the list by kind.
  • +
  • Locate the first duplicate with a “exe” kind.
  • +
  • Select it.
  • +
  • Scroll down the list to locate the last duplicate with a “exe” kind.
  • +
  • Hold Shift and click on it.
  • +
  • Press Space to mark all selected duplicates.
  • +
+
+
+

Delta Values

+

If you turn this switch on, numerical columns will display the value relative to the duplicate’s +reference instead of the absolute values. These delta values will also be displayed in a different +color, orange, so you can spot them easily. For example, if a duplicate is 1.2 MB and its reference +is 1.4 MB, the Size column will display -0.2 MB.

+

Moreover, non-numerical values will also be in orange if their value is different from their +reference, and stay black if their value is the same. Combined with column sorting in Dupes Only +mode, this allows for very powerful post-scan filtering.

+
+
+

Dupes Only and Delta Values

+

The Dupes Only mode unveil its true power when you use it with the Delta Values switch turned on. +When you turn it on, relative values will be displayed instead of absolute ones. So if, for example, +you want to remove from your results all duplicates that are more than 300 KB away from their +reference, you could sort the dupes only results by Size, select all duplicates under -300 in the +Size column, delete them, and then do the same for duplicates over 300 at the bottom of the list.

+

Same thing for non-numerical values: When Dupes Only and Delta Values are enabled at the same time, +column sorting groups rows depending on whether they’re orange or not. Example: You ran a contents +scan, but you would only like to delete duplicates that have the same filename? Sort by filename +and all dupes with their filename attribute being the same as the reference will be grouped +together, their value being in black.

+

You could also use it to change the reference priority of your duplicate list. When you make a fresh +scan, if there are no reference folders, the reference file of every group is the biggest file. If +you want to change that, for example, to the latest modification time, you can sort the dupes only +results by modification time in descending order, select all duplicates with a modification time +delta value higher than 0 and click on Make Selected into Reference. The reason why you must +make the sort order descending is because if 2 files among the same duplicate group are selected +when you click on Make Selected into Reference, only the first of the list will be made +reference, the other will be ignored. And since you want the last modified file to be reference, +having the sort order descending assures you that the first item of the list will be the last +modified.

+
+
+

Filtering

+

dupeGuru supports post-scan filtering. With it, you can narrow down your results so you can perform +actions on a subset of it. For example, you could easily mark all duplicates with their filename +containing “copy” from your results using the filter.

+

To use the filtering feature, type your filter in the “Filter” search field at the top-right corner +of the results window. What you type in that box will be applied to the whole path of every +duplicate in the results. Only duplicate groups having at least one duplicate matching the filter +will be shown.

+

When having groups where not all duplicates match the filter, we still show all duplicates of +the group. However, non-matching duplicates are in “reference mode”. Therefore, you can perform +actions like “Mark All” and be sure to only mark filtered duplicates.

+

To go back to unfiltered result, blank out the field or click on the “X”.

+

In simple mode (the default mode), whatever you type as the filter is the string used to perform the +actual filtering, with the exception of one wildcard: *. Thus, if you type “[*]” as your +filter, it will match anything with [] brackets in it, whatever is in between those brackets.

+

For more advanced filtering, you can turn “Use regular expressions when filtering” on. The filtering +feature will then use regular expressions. A regular expression is a language for matching text. +Explaining them is beyond the scope of this document. A good place to start learning it is +regular-expressions.info.

+

Matches are case insensitive in both simple and regexp mode.

+

For the filter to match, your regular expression don’t have to match the whole filename, it just +have to contain a string matching the expression.

+
+
+

Action Menu

+
+
Clear Ignore List:
+
Remove all ignored matches you added. You have to start a new scan for the +newly cleared ignore list to be effective.
+
Export Results to XHTML:
+
Take the current results, and create an XHTML file out of it. The +columns that are visible when you click on this button will be the columns present in the XHTML +file. The file will automatically be opened in your default browser.
+
Send Marked to Trash:
+
Send all marked duplicates to trash, obviously. Before proceeding, +you’ll be presented deletion options (see below).
+
Move Marked to…:
+
Prompt you for a destination, and then move all marked files to that +destination. Source file’s path might be re-created in destination, depending on the +“Copy and Move” preference.
+
Copy Marked to…:
+
Prompt you for a destination, and then copy all marked files to that +destination. Source file’s path might be re-created in destination, depending on the +“Copy and Move” preference.
+
Remove Marked from Results:
+
Remove all marked duplicates from results. The actual files will +not be touched and will stay where they are.
+
Remove Selected from Results:
+
Remove all selected duplicates from results. Note that all +selected reference files will be ignored, only duplicates can be removed with this action.
+
Make Selected into Reference:
+
Promote all selected duplicates to reference. If a duplicate is +a part of a group having a reference file coming from a reference folder (in blue color), no +action will be taken for this duplicate. If more than one duplicate among the same group are +selected, only the first of each group will be promoted.
+
Add Selected to Ignore List:
+
This first removes all selected duplicates from results, and +then add the match of that duplicate and the current reference in the ignore list. This match +will not come up again in further scan. The duplicate itself might come back, but it will be +matched with another reference file. You can clear the ignore list with the Clear Ignore List +command.
+
Open Selected with Default Application:
+
Open the file with the application associated with selected file’s type.
+
Reveal Selected in Finder:
+
Open the folder containing selected file.
+
Invoke Custom Command:
+
Invokes the external application you’ve set up in your preferences using the current selection +as arguments in the invocation.
+
Rename Selected:
+
Prompts you for a new name, and then rename the selected file.
+
+
+
+

Deletion Options

+

These options affect how duplicate deletion takes place. Most of the time, you don’t need to enable +any of them.

+
+
Link deleted files:
+

The deleted files are replaced by a link to the reference file. You have a choice of replacing +it either with a symlink or a hardlink. It’s better to read the whole +wikipedia pages about them to make a informed choice, but in short, a symlink is a shortcut to +the file’s path. If the original file is deleted or moved, the link is broken. A hardlink is a +link to the file itself. That link is as good as a “real” file. Only when all hardlinks to a +file are deleted is the file itself deleted.

+

On OSX and Linux, this feature is supported fully, but under Windows, it’s a bit complicated. +Windows XP doesn’t support it, but Vista and up support it. However, for the feature to work, +dupeGuru has to run with administrative privileges.

+
+
Directly delete files:
+
Instead of sending files to trash, directly delete them. This is used +for troubleshooting and you normally don’t need to enable this unless dupeGuru has problems +deleting files normally, something that can happens when you try to delete files on network +storage (NAS).
+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/scan.html b/help/en/scan.html new file mode 100644 index 00000000..1149d86c --- /dev/null +++ b/help/en/scan.html @@ -0,0 +1,204 @@ + + + + + + + + The scanning process — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

The scanning process

+ +

dupeGuru has 3 basic ways of scanning: Worded scans and Contents scans and +picture blocks. The first two types are for the Standard and Music +modes, the last is for the Picture mode. The scanning process is configured through the +Preference pane.

+
+

Worded scans

+

Worded scans extract a string from each file and split it into words. The string can come from two +different sources: Filename or Tags (Music Edition only).

+

When our source is music tags, we have to choose which tags to use. If, for example, we choose to +analyse artist and title tags, we’d end up with strings like +“The White Stripes - Seven Nation Army”.

+

Words are split by space characters, with all punctuation removed (some are replaced by spaces, some +by nothing) and all words lowercased. For example, the string “This guy’s song(remix)” yields +this, guys, song and remix.

+

Once this is done, the scanning dance begins. Finding duplicates is only a matter of finding how +many words in common two given strings have. If the filter hardness is, +for example, 80, it means that 80% of the words of two strings must match. To determine the +matching percentage, dupeGuru first counts the total number of words in both strings, then count +the number of words matching (every word matching count as 2), and then divide the number of words +matching by the total number of words. If the result is higher or equal than the filter hardness, +we have a duplicate match. For example, “a b c d” and “c d e” have a matching percentage of 57 +(4 words matching, 7 total words).

+
+

Fields

+

Song filenames often come with multiple and distinct parts and this can cause problems. For example, +let’s take these two songs: “Dolly Parton - I Will Always Love You” and +“Whitney Houston - I Will Always Love You”. They are clearly not the same song (they come from +different artists), but they still still have a matching score of 71%! This means that, with a naive +scanning method, we would get these songs as a false positive as soon as we try to dig a bit deeper +in our dupe hunt by lowering the threshold a bit.

+

This is why we have the “Fields” concept. Fields are separated by dashes (-). When the +“Filename - Fields” scan type is chosen, each field is compared separately. Our final matching score +will only be the lowest of all the fields. In our example, the title has a 100% match, but the +artist has a 0% match, making our final match score 0.

+

Sometimes, our song filename policy isn’t completely homogenous, which means that we can end up with +“The White Stripes - Seven Nation Army” and “Seven Nation Army - The White Stripes”. This is why +we have the “Filename - Fields (No Order)” scan type. With this scan type, all fields are compared +with each other, and the highest score is kept. Then, the final matching score is the lowest of them +all. In our case, the final matching score is 100.

+

Note: Each field is used once. Thus, “The White Stripes - The White Stripes” and +“The White Stripes - Seven Nation Army” have a match score of 0 because the second +“The White Stripes” can’t be compared with the first field of the other name because it has already +been “used up” by the first field. Our final match score would be 0.

+

Tags scanning method is always “fielded”. When choosing this scan method, we also choose which +tags are going to be compared, each being a field.

+
+
+

Word weighting

+

When enabled, this option slightly changes how matching percentage is calculated by making bigger +words worth more. With word weighting, instead of having a value of 1 in the duplicate count and +total word count, every word have a value equal to the number of characters they have. With word +weighting, “ab cde fghi” and “ab cde fghij” would have a matching percentage of 53% (19 total +characters, 10 characters matching (4 for “ab” and 6 for “cde”)).

+
+
+

Similarity matching

+

When enabled, similar words will be counted as matches. For example “The White Stripes” and +“The White Stripe” would have a match score of 100 instead of 66 with that option turned on.

+

Two words are considered similar if they can be made equal with only a few edit operations (removing +a letter, adding one etc.). The process used is not unlike the +Levenshtein distance. For the technically inclined, the actual function used is +Python’s get_close_matches with a 0.8 cutoff.

+

Warning: Use this option with caution. It is likely that you will get a lot of false positives +in your results when turning it on. However, it will help you to find duplicates that you wouldn’t +have found otherwise. The scan process also is significantly slower with this option turned on.

+
+
+
+

Contents scans

+

Contents scans are much simpler than worded scans. We read files and if the contents is exactly the +same, we consider the two files duplicates.

+

This is, of course, quite longer than comparing filenames and, to avoid needlessly reading whole +file contents, we start by looking at file sizes. After having grouped our files by size, we discard +every file that is alone in its group. Then, we proceed to read the contents of our remaining files.

+

MD5 hashes are used to compute compare contents. Yes, it is widely known that forging files having +the same MD5 hash is easy, but this file has to be knowingly forged. The possibilities of two files +having the same MD5 hash and the same size by accident is still very, very small.

+

The filter hardness preference is ignored in this scan.

+
+

Folders

+

This is a special Contents scan type. It works like a normal contents scan, but +instead of trying to find duplicate files, it tries to find duplicate folders. +A folder is duplicate to another if all files it contains have the same +contents as the other folder’s file.

+

This scan is, of course, recursive and subfolders are checked. dupeGuru keeps only the biggest +fishes. Therefore, if two folders that are considered as matching contain subfolders, these +subfolders will not be included in the final results.

+

With this mode, we end up with folders as results instead of files.

+
+
+
+

Picture blocks

+

dupeGuru Picture mode stands apart of its two friends. Its scan types are completely different. +The first one is its “Contents” scan, which is a bit too generic, hence the name we use here, +“Picture blocks”.

+

We start by opening every picture in RGB bitmap mode, then we “blockify” the picture. We create a +15x15 grid and compute the average color of each grid tile. This is the “picture analysis” phase. +It’s very time consuming and the result is cached in a database (the “picture cache”).

+

Once we’ve done that, we can start comparing them. Each tile in the grid (an average color) is +compared to its corresponding grid on the other picture and a color diff is computer (it’s simply +a sum of the difference of R, G and B on each side). All these sums are added up to a final “score”.

+

If that score is smaller or equal to 100 - threshold, we have a match.

+

A threshold of 100 adds an additional constraint that pictures have to be exactly the same (it’s +possible, due to averaging, that the tile comparison yields 0 for pictures that aren’t exactly +the same, but since “100%” suggests “exactly the same”, we discard those ocurrences). If you want +to get pictures that are very, very similar but still allow a bit of fuzzy differences, go for 99%.

+

This second part of the scan is CPU intensive and can take quite a bit of time. This task has been +made to take advatange of multi-core CPUs and has been optimized to the best of my abilities, but +the fact of the matter is that, due to the fuzziness of the task, we still have to compare every picture +to every other, making the algorithm quadratic (if N is the number of pictures to compare, the +number of comparisons to perform is N*N).

+

This algorithm is very naive, but in the field, it works rather well. If you master a better +algorithm and want to improve dupeGuru, by all means, let me know!

+
+
+

EXIF Timestamp

+

This one is easy. We read the EXIF information of every picture and extract the DateTimeOriginal +tag. If the tag is the same for two pictures, they’re considered duplicates.

+

Warning: Modified pictures often keep the same EXIF timestamp, so watch out for false positives +when you use that scan type.

+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/en/search.html b/help/en/search.html new file mode 100644 index 00000000..efd111ec --- /dev/null +++ b/help/en/search.html @@ -0,0 +1,80 @@ + + + + + + + + Search — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + + + + +
+ + +

Search

+
+ +

+ Please activate JavaScript to enable the search + functionality. +

+
+

+ From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

+
+ + + +
+ +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/help/en/searchindex.js b/help/en/searchindex.js new file mode 100644 index 00000000..9906015c --- /dev/null +++ b/help/en/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["changelog","contribute","developer/core/app","developer/core/directories","developer/core/engine","developer/core/fs","developer/core/gui/deletion_options","developer/core/gui/index","developer/core/index","developer/core/results","developer/hscommon/build","developer/hscommon/conflict","developer/hscommon/desktop","developer/hscommon/gui/base","developer/hscommon/gui/column","developer/hscommon/gui/progress_window","developer/hscommon/gui/selectable_list","developer/hscommon/gui/table","developer/hscommon/gui/text_field","developer/hscommon/gui/tree","developer/hscommon/index","developer/hscommon/jobprogress/job","developer/hscommon/jobprogress/performer","developer/hscommon/jobprogress/qt","developer/hscommon/notify","developer/hscommon/path","developer/hscommon/util","developer/index","faq","folders","index","preferences","quick_start","reprioritize","results","scan"],envversion:53,filenames:["changelog.rst","contribute.rst","developer\\core\\app.rst","developer\\core\\directories.rst","developer\\core\\engine.rst","developer\\core\\fs.rst","developer\\core\\gui\\deletion_options.rst","developer\\core\\gui\\index.rst","developer\\core\\index.rst","developer\\core\\results.rst","developer\\hscommon\\build.rst","developer\\hscommon\\conflict.rst","developer\\hscommon\\desktop.rst","developer\\hscommon\\gui\\base.rst","developer\\hscommon\\gui\\column.rst","developer\\hscommon\\gui\\progress_window.rst","developer\\hscommon\\gui\\selectable_list.rst","developer\\hscommon\\gui\\table.rst","developer\\hscommon\\gui\\text_field.rst","developer\\hscommon\\gui\\tree.rst","developer\\hscommon\\index.rst","developer\\hscommon\\jobprogress\\job.rst","developer\\hscommon\\jobprogress\\performer.rst","developer\\hscommon\\jobprogress\\qt.rst","developer\\hscommon\\notify.rst","developer\\hscommon\\path.rst","developer\\hscommon\\util.rst","developer\\index.rst","faq.rst","folders.rst","index.rst","preferences.rst","quick_start.rst","reprioritize.rst","results.rst","scan.rst"],objects:{"core.app":{DupeGuru:[2,1,1,""]},"core.app.DupeGuru":{add_directory:[2,2,1,""],add_selected_to_ignore_list:[2,2,1,""],apply_filter:[2,2,1,""],copy_or_move_marked:[2,2,1,""],delete_marked:[2,2,1,""],directories:[2,3,1,""],export_to_csv:[2,2,1,""],export_to_xhtml:[2,2,1,""],invoke_custom_command:[2,2,1,""],load:[2,2,1,""],load_from:[2,2,1,""],make_selected_reference:[2,2,1,""],mark_all:[2,2,1,""],mark_dupe:[2,2,1,""],mark_invert:[2,2,1,""],mark_none:[2,2,1,""],open_selected:[2,2,1,""],purge_ignore_list:[2,2,1,""],remove_directories:[2,2,1,""],remove_duplicates:[2,2,1,""],remove_marked:[2,2,1,""],remove_selected:[2,2,1,""],rename_selected:[2,2,1,""],reprioritize_groups:[2,2,1,""],result_table:[2,3,1,""],results:[2,3,1,""],save_as:[2,2,1,""],selected_dupes:[2,3,1,""],start_scanning:[2,2,1,""],without_ref:[2,2,1,""]},"core.directories":{AlreadyThereError:[3,4,1,""],Directories:[3,1,1,""],DirectoryState:[3,1,1,""],InvalidPathError:[3,4,1,""]},"core.directories.Directories":{add_path:[3,2,1,""],get_files:[3,2,1,""],get_folders:[3,2,1,""],get_state:[3,2,1,""],get_subfolders:[3,5,1,""],has_any_file:[3,2,1,""],load_from_file:[3,2,1,""],save_to_file:[3,2,1,""],set_state:[3,2,1,""]},"core.engine":{Group:[4,1,1,""],Match:[4,1,1,""],build_word_dict:[4,6,1,""],compare:[4,6,1,""],compare_fields:[4,6,1,""],get_groups:[4,6,1,""],getmatches:[4,6,1,""],getmatches_by_contents:[4,6,1,""],merge_similar_words:[4,6,1,""],reduce_common_words:[4,6,1,""]},"core.engine.Group":{add_match:[4,2,1,""],discard_matches:[4,2,1,""],dupes:[4,3,1,""],get_match_of:[4,2,1,""],ordered:[4,3,1,""],percentage:[4,3,1,""],prioritize:[4,2,1,""],ref:[4,3,1,""],switch_ref:[4,2,1,""],unordered:[4,3,1,""]},"core.engine.Match":{first:[4,3,1,""],percentage:[4,3,1,""],second:[4,3,1,""]},"core.fs":{AlreadyExistsError:[5,4,1,""],FSError:[5,4,1,""],File:[5,1,1,""],Folder:[5,1,1,""],InvalidDestinationError:[5,4,1,""],InvalidPath:[5,4,1,""],OperationError:[5,4,1,""],get_file:[5,6,1,""],get_files:[5,6,1,""]},"core.fs.File":{can_handle:[5,7,1,""],get_display_info:[5,2,1,""]},"core.fs.Folder":{can_handle:[5,7,1,""]},"core.gui":{deletion_options:[6,0,0,"-"]},"core.gui.deletion_options":{DeletionOptions:[6,1,1,""],DeletionOptionsView:[6,1,1,""]},"core.gui.deletion_options.DeletionOptions":{direct:[6,3,1,""],link_deleted:[6,3,1,""],show:[6,2,1,""],supports_links:[6,2,1,""],use_hardlinks:[6,3,1,""]},"core.gui.deletion_options.DeletionOptionsView":{set_hardlink_option_enabled:[6,2,1,""],show:[6,2,1,""],update_msg:[6,2,1,""]},"core.results":{Results:[9,1,1,""]},"core.results.Results":{apply_filter:[9,2,1,""],dupes:[9,3,1,""],get_group_of_duplicate:[9,2,1,""],groups:[9,3,1,""],load_from_xml:[9,2,1,""],make_ref:[9,2,1,""],perform_on_marked:[9,2,1,""],remove_duplicates:[9,2,1,""],save_to_xml:[9,2,1,""],sort_dupes:[9,2,1,""],sort_groups:[9,2,1,""]},"hscommon.build":{add_to_pythonpath:[10,6,1,""],build_debian_changelog:[10,6,1,""],build_dmg:[10,6,1,""],copy_packages:[10,6,1,""],ensure_empty_folder:[10,6,1,""],filereplace:[10,6,1,""],print_and_do:[10,6,1,""]},"hscommon.conflict":{get_conflicted_name:[11,6,1,""],get_unconflicted_name:[11,6,1,""],is_conflicted:[11,6,1,""],smart_copy:[11,6,1,""],smart_move:[11,6,1,""]},"hscommon.desktop":{open_path:[12,6,1,""],open_url:[12,6,1,""],reveal_path:[12,6,1,""],special_folder_path:[12,6,1,""]},"hscommon.gui":{base:[13,0,0,"-"],column:[14,0,0,"-"],progress_window:[15,0,0,"-"],selectable_list:[16,0,0,"-"],table:[17,0,0,"-"],text_field:[18,0,0,"-"],tree:[19,0,0,"-"]},"hscommon.gui.base":{GUIObject:[13,1,1,""]},"hscommon.gui.base.GUIObject":{_view_updated:[13,2,1,""],view:[13,3,1,""]},"hscommon.gui.column":{Column:[14,1,1,""],Columns:[14,1,1,""],ColumnsView:[14,1,1,""],PrefAccessInterface:[14,1,1,""]},"hscommon.gui.column.Column":{default_visible:[14,3,1,""],default_width:[14,3,1,""],display:[14,3,1,""],logical_index:[14,3,1,""],name:[14,3,1,""],optional:[14,3,1,""],ordered_index:[14,3,1,""],visible:[14,3,1,""],width:[14,3,1,""]},"hscommon.gui.column.Columns":{_view_updated:[14,2,1,""],colnames:[14,3,1,""],column_by_index:[14,2,1,""],column_by_name:[14,2,1,""],column_display:[14,2,1,""],column_is_visible:[14,2,1,""],column_width:[14,2,1,""],columns_count:[14,2,1,""],columns_to_right:[14,2,1,""],menu_items:[14,2,1,""],move_column:[14,2,1,""],ordered_columns:[14,3,1,""],reset_to_defaults:[14,2,1,""],resize_column:[14,2,1,""],restore_columns:[14,2,1,""],save_columns:[14,2,1,""],set_column_order:[14,2,1,""],set_column_visible:[14,2,1,""],set_default_width:[14,2,1,""],toggle_menu_item:[14,2,1,""]},"hscommon.gui.column.ColumnsView":{restore_columns:[14,2,1,""],set_column_visible:[14,2,1,""]},"hscommon.gui.column.PrefAccessInterface":{get_default:[14,2,1,""],set_default:[14,2,1,""]},"hscommon.gui.progress_window":{ProgressWindow:[15,1,1,""],ProgressWindowView:[15,1,1,""]},"hscommon.gui.progress_window.ProgressWindow":{cancel:[15,2,1,""],jobdesc_textfield:[15,3,1,""],progressdesc_textfield:[15,3,1,""],pulse:[15,2,1,""],run:[15,2,1,""]},"hscommon.gui.progress_window.ProgressWindowView":{close:[15,2,1,""],set_progress:[15,2,1,""],show:[15,2,1,""]},"hscommon.gui.selectable_list":{GUISelectableList:[16,1,1,""],GUISelectableListView:[16,1,1,""],Selectable:[16,1,1,""],SelectableList:[16,1,1,""]},"hscommon.gui.selectable_list.GUISelectableList":{_on_change:[16,2,1,""],_update_selection:[16,2,1,""],_view_updated:[16,2,1,""]},"hscommon.gui.selectable_list.GUISelectableListView":{refresh:[16,2,1,""],update_selection:[16,2,1,""]},"hscommon.gui.selectable_list.Selectable":{_update_selection:[16,2,1,""],select:[16,2,1,""],selected_index:[16,3,1,""],selected_indexes:[16,3,1,""]},"hscommon.gui.selectable_list.SelectableList":{_on_change:[16,2,1,""],append:[16,2,1,""],insert:[16,2,1,""],remove:[16,2,1,""]},"hscommon.gui.table":{GUITable:[17,1,1,""],GUITableView:[17,1,1,""],Row:[17,1,1,""],Table:[17,1,1,""]},"hscommon.gui.table.GUITable":{"delete":[17,2,1,""],_do_add:[17,2,1,""],_do_delete:[17,2,1,""],_fill:[17,2,1,""],_is_edited_new:[17,2,1,""],_restore_selection:[17,2,1,""],add:[17,2,1,""],can_edit_cell:[17,2,1,""],cancel_edits:[17,2,1,""],edited:[17,3,1,""],refresh:[17,2,1,""],save_edits:[17,2,1,""],sort_by:[17,2,1,""]},"hscommon.gui.table.GUITableView":{refresh:[17,2,1,""],start_editing:[17,2,1,""],stop_editing:[17,2,1,""]},"hscommon.gui.table.Row":{can_edit:[17,2,1,""],can_edit_cell:[17,2,1,""],get_cell_value:[17,2,1,""],load:[17,2,1,""],save:[17,2,1,""],set_cell_value:[17,2,1,""],sort_key_for_column:[17,2,1,""]},"hscommon.gui.table.Table":{append:[17,2,1,""],footer:[17,3,1,""],header:[17,3,1,""],insert:[17,2,1,""],remove:[17,2,1,""],row_count:[17,3,1,""],rows:[17,3,1,""],selected_row:[17,3,1,""],selected_rows:[17,3,1,""],sort_by:[17,2,1,""]},"hscommon.gui.text_field":{TextField:[18,1,1,""],TextFieldView:[18,1,1,""]},"hscommon.gui.text_field.TextField":{_format:[18,2,1,""],_parse:[18,2,1,""],_update:[18,2,1,""],_view_updated:[18,2,1,""],refresh:[18,2,1,""],text:[18,3,1,""],value:[18,3,1,""]},"hscommon.gui.text_field.TextFieldView":{refresh:[18,2,1,""]},"hscommon.gui.tree":{Node:[19,1,1,""],Tree:[19,1,1,""]},"hscommon.gui.tree.Node":{append:[19,2,1,""],children_count:[19,3,1,""],clear:[19,2,1,""],find:[19,2,1,""],findall:[19,2,1,""],get_node:[19,2,1,""],get_path:[19,2,1,""],insert:[19,2,1,""],name:[19,3,1,""],parent:[19,3,1,""],path:[19,3,1,""],root:[19,3,1,""]},"hscommon.gui.tree.Tree":{_select_nodes:[19,2,1,""],_selected_nodes:[19,3,1,""],_view_updated:[19,2,1,""],clear:[19,2,1,""],selected_node:[19,3,1,""],selected_nodes:[19,3,1,""],selected_path:[19,3,1,""],selected_paths:[19,3,1,""]},"hscommon.jobprogress":{job:[21,0,0,"-"],performer:[22,0,0,"-"],qt:[23,0,0,"-"]},"hscommon.jobprogress.job":{Job:[21,1,1,""],NullJob:[21,1,1,""]},"hscommon.jobprogress.job.Job":{_do_update:[21,2,1,""],_subjob_callback:[21,2,1,""],iter_with_progress:[21,2,1,""],set_progress:[21,2,1,""],start_job:[21,2,1,""],start_subjob:[21,2,1,""]},"hscommon.jobprogress.performer":{ThreadedJobPerformer:[22,1,1,""]},"hscommon.jobprogress.performer.ThreadedJobPerformer":{reraise_if_error:[22,2,1,""]},"hscommon.jobprogress.qt":{Progress:[23,1,1,""]},"hscommon.notify":{Broadcaster:[24,1,1,""],Listener:[24,1,1,""],Repeater:[24,1,1,""]},"hscommon.notify.Broadcaster":{notify:[24,2,1,""]},"hscommon.notify.Listener":{bind_messages:[24,2,1,""],connect:[24,2,1,""],disconnect:[24,2,1,""]},"hscommon.path":{Path:[25,1,1,""],log_io_error:[25,6,1,""],pathify:[25,6,1,""]},"hscommon.path.Path":{is_parent_of:[25,2,1,""],name:[25,3,1,""],parent:[25,2,1,""]},"hscommon.util":{FileOrPath:[26,1,1,""],RE_INVALID_XML_SUB:[26,6,1,""],allsame:[26,6,1,""],dedupe:[26,6,1,""],delete_files_with_pattern:[26,6,1,""],delete_if_empty:[26,6,1,""],ensure_file:[26,6,1,""],ensure_folder:[26,6,1,""],escape:[26,6,1,""],extract:[26,6,1,""],find_in_path:[26,6,1,""],first:[26,6,1,""],flatten:[26,6,1,""],format_size:[26,6,1,""],format_time:[26,6,1,""],format_time_decimal:[26,6,1,""],get_file_ext:[26,6,1,""],iterconsume:[26,6,1,""],iterdaterange:[26,6,1,""],minmax:[26,6,1,""],modified_after:[26,6,1,""],multi_replace:[26,6,1,""],nonone:[26,6,1,""],open_if_filename:[26,6,1,""],pluralize:[26,6,1,""],rem_file_ext:[26,6,1,""],stripfalse:[26,6,1,""],trailiter:[26,6,1,""],tryint:[26,6,1,""]},core:{app:[2,0,0,"-"],directories:[3,0,0,"-"],engine:[4,0,0,"-"],fs:[5,0,0,"-"],gui:[7,0,0,"-"],results:[9,0,0,"-"]},hscommon:{build:[10,0,0,"-"],conflict:[11,0,0,"-"],desktop:[12,0,0,"-"],notify:[24,0,0,"-"],path:[25,0,0,"-"],util:[26,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","attribute","Python attribute"],"4":["py","exception","Python exception"],"5":["py","staticmethod","Python static method"],"6":["py","function","Python function"],"7":["py","classmethod","Python class method"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute","4":"py:exception","5":"py:staticmethod","6":"py:function","7":"py:classmethod"},terms:{"15x15":35,"32bit":0,"64bit":0,"ale\u0161":0,"byte":[0,26],"case":[0,1,4,13,16,17,28,31,33,34,35],"catch":25,"char":26,"class":[2,3,4,5,6,9,13,14,15,16,17,18,19,21,22,23,24,25,26,27],"const":12,"default":[0,12,13,14,16,17,18,19,26,28,29,32,34],"enum":3,"export":[0,2,34],"final":[27,28,31,35],"function":[4,9,10,15,17,21,22,24,25,26,27,35],"import":[0,2,16,33],"int":[2,4,6,15,16,17,19,21,26],"long":[0,4,15],"new":[0,16,17,18,29,34],"public":17,"return":[2,3,4,5,6,9,11,12,14,15,17,18,19,21,22,25,26,27],"short":[17,34],"static":3,"switch":[0,4,34],"t\u00e4tzner":0,"true":[2,6,9,13,14,15,17,19,26,34],"try":[0,1,5,28,31,34,35],"while":[0,1,17,21],Added:0,Adding:17,And:[28,34],But:[0,1,17],Doing:[13,14,18,19],For:[1,4,6,7,14,15,16,17,18,19,21,27,28,31,33,34,35],Its:[18,34,35],NAS:[28,34],Not:[6,14,15,16,17,18],That:[1,13,14,24,32,34],The:[0,1,2,3,4,5,9,10,11,12,13,14,15,16,17,18,19,21,26,27,29,30,31,32,33,34],Their:17,Then:[1,3,17,27,35],There:[13,17,21,27,28,32],These:[0,2,14,31,34],Use:[10,13,14,18,19,21,31,34,35],Used:14,Using:[2,16],Was:0,Will:35,With:[17,34,35],Yes:35,__getitem__:17,__init__:21,_create_job:22,_do_add:17,_do_delet:17,_do_upd:21,_fill:17,_foobar:17,_format:18,_is_edited_new:17,_job_run:22,_on_chang:16,_pars:18,_restore_select:17,_run_thread:22,_select_nod:19,_selected_nod:19,_start_job:27,_subjob_callback:21,_updat:18,_update_select:[16,17],_view_upd:[13,14,16,18,19],abil:[0,35],abl:[1,4,13],abort:17,about:[0,1,28,29,30,32],abov:32,absolut:[26,28,31,34],accept:6,access:14,accid:35,accident:0,accord:[2,3,4,9,14,17,33,34],account:1,act:[2,13,18],action:[0,2,13,15,28,30,31,32,33],activ:[0,6,28],actual:[1,6,13,14,15,16,17,18,25,28,34,35],add:[0,2,3,4,5,10,17,19,26,28,29,32,33,34,35],add_directori:[2,27],add_match:4,add_path:3,add_progress:21,add_selected_to_ignore_list:2,add_to_pythonpath:10,added:[0,1,3,4,9,11,17,27,29,31,34,35],adding:[0,19,21,26,35],addit:[15,19,33,35],adjust:17,administr:34,advanc:[28,34],advatang:35,advis:15,affect:[0,34],after:[0,4,5,13,14,16,17,18,19,21,22,26,28,29,31,35],afterward:[16,26],again:[0,1,21,24,28,34],agin:24,agre:1,alarm:0,algorithm:[0,28,35],all:[0,1,2,3,4,9,10,14,15,16,17,19,24,26,27,29,30,31,32,33,34,35],allow:[0,15,17,18,28,31,33,34,35],allsam:26,almost:25,alon:35,alreadi:[0,1,3,5,11,25,26,31,35],alreadyexistserror:5,alreadythereerror:3,alright:27,also:[0,2,3,4,6,9,14,15,17,18,26,28,29,30,31,34,35],altern:[17,29],although:[1,30,34],alwai:[1,2,4,17,18,19,26,27,28,34,35],among:[4,34],amount:27,analys:35,analysi:35,analyz:0,anh:0,ani:[1,3,7,9,14,15,17,22,29,31,34],annot:25,annoy:0,anoth:[13,21,34,35],answer:13,anymor:[0,1],anyth:[16,18,27,28,34],anywai:0,apart:35,apertur:0,api:30,app:[0,1,8,9,10,14,15,19,27],app_path:10,appdata:2,append:[16,17,19],appli:[0,2,3,9,34],applic:[0,2,3,10,12,28,30,31,34],apply_filt:[2,9],appnam:12,appreci:1,approach:7,appropri:[2,5,6,15,16,17],arbitrari:[0,15,17,18],arch:0,archive2015:0,aren:[0,31,35],arg1:22,arg2:22,arg:[15,21],argument:[12,14,15,21,25,33,34],armenian:[0,30],armi:35,around:[1,5,16,19,27],arrow:33,artist:[4,35],asc:9,ascii:0,ask:[0,30],aspect:21,assign:13,associ:[2,12,34],assum:[26,34],assur:34,async:2,atom:27,attr:[3,17,19],attract:1,attribut:[0,2,4,9,14,17,18,19,34],attributeerror:[0,17],attrnam:17,audio:[0,29],author:1,auto:0,automat:[0,16,21,26,29,33,34],avail:[29,30,33],averag:[4,35],avoid:[0,13,15,26,35],awai:[30,34],awar:[0,27],back:[0,9,34],backend:0,bad:[0,2],bar:[0,15,25,30,33],base:[0,1,17,20,27],basic:[27,29,32,35],baz:25,becam:0,becaus:[1,3,4,6,13,14,15,17,19,21,26,28,31,34,35],becom:[2,16],been:[0,1,4,5,11,13,14,15,16,17,18,19,26,28,31,35],befor:[6,13,15,16,17,19,26,29,34],begin:[0,17,21,35],behav:[16,17,19,31],behavior:[0,6,17,19],being:[0,1,2,3,4,14,17,19,29,34,35],belong:[9,14],below:[26,28,29,33,34],best:[28,34,35],better:[1,34,35],between:[0,4,11,15,26,34],beyond:[31,34],big:[0,1,27],bigger:[1,35],biggest:[33,34,35],bin:[0,32,34],bind:[0,13,24],bind_messag:24,bit:[0,1,2,4,19,25,34,35],bitmap:35,bitrat:30,black:34,bland:19,blank:34,block:[0,30,31],blockifi:35,blue:[0,7,28,34],bool:[2,3,4,6,9,17,19],both:[10,18,26,28,34,35],bottom:[17,34],bound:[16,26],box:[19,30,31,32,34],bracket:[11,28,34],brain:24,branch:[1,30],brazilian:0,bring:[0,34],broadcast:24,broken:[0,34],browser:[12,34],bsd:0,bug:[0,1,30],bugfix:[1,27],build:[0,1,20,27],build_debian_changelog:10,build_dmg:10,build_word_dict:4,buildabl:27,built:[4,18,27,28],bump:0,bundl:0,button:[0,6,15,29,32,33,34],cach:[0,28,35],calcul:[17,35],call:[0,2,3,4,5,9,13,14,15,16,17,18,19,21,22,24,25,27],callback:[14,15,16,17,21],caller:22,came:0,can:[0,1,2,3,4,5,11,12,14,15,16,17,18,19,21,24,26,29,30,31,32,33,34,35],can_edit:17,can_edit_:17,can_edit_cel:17,can_handl:5,cancel:[0,6,9,15,17],cancel_edit:17,candid:[4,5],cannot:[5,28,29,34],capabl:28,care:[2,9,15],categori:33,caus:[0,1,9,35],caution:35,cde:35,ceil:0,cell:[0,7,17],central:27,certain:0,chain:19,chanc:[1,17],chang:[0,1,2,6,14,15,16,17,18,29,34,35],changelog:[10,30],changelogpath:10,charact:[0,26,31,35],check:[17,19,21,31,34,35],checkbox:6,checkout:1,checkup:5,child:19,children:[19,21],children_count:19,chines:0,choic:34,choos:[0,29,35],chosen:[0,3,26,35],civil:14,classmethod:5,cleanli:14,clear:[0,1,19,34],clearer:0,clearli:35,clever:33,click:[0,14,15,28,29,32,33,34],close:[2,15,26],cmd:[0,10],cocoa:[0,7,27],code:[1,6,7,13,14,15,16,17,18,19,27],codebas:27,collect:[0,9,10],colnam:14,color:[0,34,35],column:[0,2,7,17,20,27,28,29,34],column_by_index:14,column_by_nam:14,column_displai:14,column_is_vis:14,column_nam:17,column_width:14,columns_count:14,columns_to_right:14,columnsview:14,com:28,combin:34,combobox:[16,33],comboboxmodel:0,come:[0,33,34,35],command:[0,2,31,34],comment:1,commit:[1,17,27],common:[4,16,35],commun:1,compar:[4,35],compare_field:4,comparison:[0,28,29,31,35],compat:0,complement:0,complet:[0,15,35],complex:[1,17,26],complic:34,compos:34,comput:[4,17,19,28,30,35],concept:[4,35],conf:28,config:28,configur:[0,2,14,35],confirm:2,conflict:[20,27,31],confus:0,conlict:11,connect:24,consid:[3,4,17,26,31,35],constraint:35,consum:[7,35],contact:1,contain:[0,1,3,4,5,9,12,14,15,17,26,29,30,31,34,35],content:[0,4,6,16,17,18,19,29,30],context:[0,1],contribut:30,control:[6,13,14,19,30,34],conveni:14,convent:17,convers:0,convert:[0,25,26],cool:28,coordin:2,copi:[0,2,5,10,11,30,31,34],copy_or_move_mark:2,copy_packag:10,core:[0,30,35],corner:[28,34],correct:0,correctli:[0,2,14],correspond:[3,26,35],corrupt:0,cost:28,could:[17,21,28,34],couldn:0,count:[0,4,17,21,26,30,35],coupl:[0,6,14],cours:[1,4,11,15,17,29,35],cpu:[28,35],crash:[0,1,13],creat:[0,1,2,4,9,17,22,26,28,31,34,35],create_link:10,creation:0,criteria:[0,33],criterion:33,cross:[7,13,14,15,16,17,18,19],csv:[0,2],current:[1,2,9,12,14,17,18,19,21,27,28,34],custom:[0,19,31,34],customcommand:2,customiz:28,cutoff:35,czech:0,dai:26,danc:35,dash:35,data:[2,5,10,13,17,28],databas:35,date:[0,2,28],datetimeorigin:35,daunt:1,dead:24,deal:[11,27],dealloc:13,debian:10,debug:[0,28],decid:[5,6],decim:26,decor:25,dedup:26,dee:0,deeper:35,def:25,default_vis:14,default_width:14,defin:[6,26,28],delet:[0,3,4,5,6,17,26,29,30,31],delete_files_with_pattern:26,delete_if_empti:26,delete_mark:2,deletion_opt:[7,8],deletionopt:6,deletionoptionsview:6,delta:[0,5,9,28,30,33],depend:[0,7,11,14,28,31,34],desc:[17,21],desc_format:21,descend:34,describ:[1,3],descript:[1,21],descriptor:0,design:[0,1,7,19,27,28],desir:[14,26],desktop:[20,27],dest:10,dest_path:[10,11],destfil:10,destfold:10,destin:[0,5,31,34],detail:[0,17,27,29,34],detect:[0,22,28],determin:[2,4,10,12,28,29,31,33,34,35],detinov:0,develop:30,dialog:[0,2,3,6,15,33],dict:[4,5],dictat:16,didn:[4,5,9,28],dif:31,diff:35,differ:[4,6,17,18,27,28,31,32,34,35],difficult:[1,27],difflib:4,dig:35,digit:26,dimens:31,direct:6,directli:[6,18,26,28,29,31,34],directori:[0,2,5,8,26,27,29,31],directoryst:3,disabl:[0,6,13,30,32,34],discard:[0,26,30,35],discard_match:4,disconnect:24,displai:[0,5,14,17,18,19,34],display_nam:14,distanc:35,distinct:35,distribut:10,divid:35,dmg:10,do_add:17,document:[0,1,6,14,15,16,17,18,30,31,34],doe:[0,3,7,15,16,17,18,26,28,33],doesn:[1,4,7,14,16,17,26,27,28,33,34],doing:[1,6,10,21],dolli:35,don:[0,1,2,3,6,10,13,16,17,19,21,26,30,31,34],done:[2,17,29,35],dostuff:26,dot:26,doubl:[0,13,34],doubt:1,down:[17,34],download:30,drag:[0,29,32,33],dramat:0,drive:21,drop:[0,32,33],due:[0,35],dupe:[0,2,4,5,6,9,26,27,28,29,30,31,33,35],dupeguru:[0,2,8,27,29,31,32,33,34,35],duplic:[0,2,4,9,27,29,30,31,32,35],dupra:1,dure:[0,2,9,15,26],dutch:0,dynam:6,each:[0,2,4,5,9,14,17,19,24,25,28,30,33,34,35],easi:[7,28,35],easili:[28,30,34],edit:[0,1,4,17,28,32,34,35],effect:[13,17,26,34],effici:0,effort:1,either:[4,7,17,28,32,34],elegantli:0,element:[2,8,16,17,18,25,26],els:[17,18],elsewher:28,email:1,empti:[0,9,10,16,17,19,26,31],enabl:[0,6,14,15,16,17,19,28,31,34,35],enclos:31,end:[0,1,4,9,10,14,15,16,17,19,26,28,29,33,35],enforc:19,engin:[0,8,27],enough:[1,28],ensur:[4,13,16,17,18,25],ensure_empty_fold:10,ensure_fil:26,ensure_fold:26,entireti:31,env:10,environmenterror:9,equal:[4,15,35],equival:4,eric:0,err:15,error:[0,2,10,15,22,27],error_func:15,escap:26,escape_with:26,especi:0,etc:[2,7,13,14,26,27,28,35],even:[0,1,14,19,28],everi:[1,2,4,21,25,26,27,28,29,32,34,35],everyth:2,exact:[0,4,28],exactli:[26,28,29,35],examin:32,exampl:[1,2,4,7,10,13,16,17,19,21,22,25,26,27,28,31,33,34,35],except:[3,4,5,15,31,34],exclud:[0,3,10,17,29],exclus:0,exe:[31,34],execut:[10,31],exif:[28,30],exist:[0,1,2,3,5,10,14,17,26,31],expect:[6,14,15,16,17,18],experi:1,explain:[31,34],explic:25,explicitli:29,export_to_csv:2,export_to_xhtml:2,express:[0,31,34],ext:31,extens:[0,10,25,26,31,34],extern:[31,34],extra_ignor:10,extract:[9,26,35],fact:[0,14,17,28,35],fail:[1,26,28],fairwar:0,fallback_valu:14,fals:[0,2,4,6,9,10,13,14,16,17,22,25,26,32,34,35],famou:15,far:19,fashion:[6,17],faster:[3,28],featur:[0,1,17,27,29,30,31,34],feedback:0,fetch:[0,7,17],few:[0,27,35],fghi:35,fghij:35,field:[0,8,18,28,34],figueiredo:0,figur:1,file:[0,1,2,3,4,5,9,11,12,26,27,29,30,31,32,33,34,35],file_or_path:26,fileclass:[3,5],filenam:[0,2,9,10,11,25,26,28,31,33,34,35],fileorpath:26,filereplac:10,files_to_delet:26,fill:[16,17,27],filter:[0,2,9,30,31,35],filter_str:9,find:[0,3,4,19,28,29,30,35],find_in_path:26,findal:19,finder:[0,34],fine:29,finish:[15,34],finish_func:15,first:[1,2,3,4,15,16,17,19,22,26,27,28,29,30,33,34,35],first_el:26,first_path:26,firstfil:27,fish:35,fit:1,fix:[0,1,10,28],fix_vers:10,flag:[4,6,13],flatten:26,flaw:27,focu:0,focus:17,folder:[0,2,3,5,10,12,26,30,31,32,33,34],folder_path:26,folderclass:3,follow:[2,14,15,17,19,33],font:0,foo:[25,33],foobar:[17,31],foolproof:21,footer:17,forcepow:26,forg:35,form:34,format:[0,1,17,18,26,31],format_s:26,format_tim:26,format_time_decim:26,forum:28,forward:1,found:[0,4,29,35],frank:0,free:4,freez:0,french:[0,30],frequent:[17,30],fresh:[1,17,34],friend:35,from:[0,1,2,3,4,7,9,14,15,17,18,19,21,24,26,27,29,30,31,32,34,35],from_:17,from_vers:10,front:[11,14,26],frozen:15,fserror:5,fset:17,fsobject:5,fulli:34,func:[9,11,24,25],funki:10,further:34,fuzzi:[0,17,28,29,35],fuzzili:[4,28],gabriel:0,gave:[4,15],gener:[3,14,27,35],german:[0,30],get:[0,1,3,4,6,13,16,17,18,19,27,28,32,33,35],get_cell_valu:17,get_close_match:[4,35],get_conflicted_nam:11,get_default:14,get_display_info:5,get_fil:[3,5,9],get_file_ext:26,get_fold:3,get_group:[4,27],get_group_of_dupl:9,get_match_of:4,get_nod:19,get_path:19,get_stat:3,get_subfold:3,get_unconflicted_nam:11,getattr:17,getmatch:[4,27],getmatches_by_cont:4,ghost:0,giraff:4,git:[1,27],github:[0,1,28],give:[14,17,28],given:[1,19,35],glitch:0,glob:26,going:[0,1,4,24,26,27,35],good:[1,30,31,34],gplv3:0,greatli:0,greek:0,gregor:0,grid:35,ground:19,group:[0,2,4,5,6,9,27,28,29,30,31,32,33,35],gui:[0,2,8,20,27,35],guid:[1,30],guidanc:30,guiobject:[13,14,15,16,17,18,19],guiselectablelist:16,guiselectablelistview:16,guitabl:17,guitableview:17,hackish:17,had:[0,9,29],handi:[21,25,34],handl:[0,5,19,31],happen:[0,2,10,15,22,34],happi:1,hard:[0,30,31,34,35],hardcod:[0,28],harder:28,hardlink:[0,6,31,34],has:[0,4,5,6,7,13,14,16,17,18,19,26,27,28,29,30,31,33,34,35],has_any_fil:3,hash:35,have:[0,1,3,4,7,11,13,14,15,17,18,19,21,24,26,29,30,31,32,33,34,35],haven:15,header:17,heck:27,held:[2,16],help:[0,1,10,27,28,32,34,35],henc:35,here:[0,13,17,19,28,31,35],high:2,higher:[14,26,34,35],highest:[30,33,35],highlight:34,him:6,his:17,hold:[2,3,4,5,7,14,17,34],homepag:30,homogen:35,hopefulli:27,host:[2,28],hour:0,houston:35,how:[0,1,2,3,11,21,30,31,34,35],howev:[1,4,13,14,18,19,21,27,28,34,35],hrant:0,hscommon:[3,4,9,27],html:0,http:0,hunt:35,icon:0,idea:[1,30],identifi:15,ignor:[0,2,31,34,35],ignore_list:2,igor:0,immedi:[6,28],immens:1,immut:14,implement:[1,17,19,27],impli:17,improv:[0,1,35],inaccuraci:0,inclin:35,includ:[1,4,10,17,27,28,29,35],include_self:19,inconveni:0,inde:[17,32],indent:[32,34],independ:4,indetermin:15,index:[2,14,16,17,19,30],index_path:19,individu:[17,28],infil:[3,9,26],infinit:19,info:[0,5,12,31,34],inform:[1,7,12,29,34,35],ingor:12,inherit:29,init:[13,19],initi:[0,13,14,15,16,17,18,19,24,29],initialis:14,inlin:17,inod:31,input:[18,29],insensit:[0,34],insert:[16,17,19],insert_index:17,insid:28,instal:31,instanc:[2,4,9,13,15,17,27],instanti:[2,13],instead:[0,2,4,11,19,21,24,29,34,35],instruct:1,integr:19,intens:35,inter:[24,27],interest:1,interfac:[0,6,13,14,15,16,17,18,27],intern:[0,4],internation:0,introduc:0,invalid:[3,5],invaliddestinationerror:5,invalidpath:5,invalidpatherror:3,invert:2,invoc:[0,34],invok:[2,31,34],invoke_custom_command:2,involv:[0,24],ioerror:25,iphoto:0,irrelev:28,is_conflict:11,is_en:6,is_mark:14,is_parent_of:25,is_ref:3,isn:[1,4,13,14,17,18,19,35],issu:[0,1,28],italian:0,item1:26,item2:26,item:[0,4,14,16,17,26,29,33,34],iter:[16,21,26],iter_with_progress:21,iterconsum:26,iterdaterang:26,its:[1,2,5,6,7,9,12,13,14,15,16,17,19,24,28,29,30,31,34,35],itself:34,itun:0,job:[0,2,3,4,9,15,20,22,30],job_proport:21,jobcount:21,jobdesc_textfield:15,jobid:15,jobprogress:[3,4,9,20,27],jumpi:0,just:[0,2,9,13,14,17,21,28,32,34],keep:[0,28,30,34,35],kei:[2,4,9,14,17],kept:[4,16,17,26,29,35],key_func:4,keybind:0,keyword:17,kind:[0,1,15,16,17,28,31,34],know:[1,14,17,21,27,32,35],knowingli:35,known:[28,35],korean:0,koutilelli:0,kwarg:[10,21],kyril:0,label:[1,15],lack:[1,29],languag:[1,30,34],larg:0,last:[0,2,14,17,25,34,35],late:1,later:17,latest:[2,27,30,34],latin:0,launch:[0,29,32],layer:[7,13,15],lead:19,learn:[1,31,34],least:[28,34],left:[14,33],leftmost:26,legaci:1,len:[17,19,21],length:[0,21,26],let:[1,4,14,15,27,28,32,35],letter:[28,35],level:[2,4,17,19],levenshtein:35,librari:28,licens:0,lies:17,lifetim:13,lightweight:21,like:[0,1,2,4,13,16,17,19,26,27,28,34,35],limit:0,line:31,link:[6,17,19,34],link_delet:6,linux:[0,28,31,34],lion:0,list:[0,2,3,4,5,9,14,16,17,19,26,27,30,33,34],listdir:25,listen:24,littl:[0,30,34],live:[27,30],load:[0,2,3,9,17],load_from:2,load_from_fil:3,load_from_xml:9,local:[0,28],localis:0,locat:[0,30,34],log:[25,28],log_io_error:25,logic:[7,19],logical_index:14,longer:[0,4,35],longest:0,look:[2,17,27,28,30,32,35],loop:[15,19,26],lose:0,lost:[0,17],lot:[0,1,21,27,28,32,35],love:35,low:[0,28,34],lower:[31,35],lowercas:[26,35],lowest:[4,35],mac:[0,28],machin:0,maco:0,made:[0,34,35],magic:17,main:[0,1,15,18,27,29],mainten:1,make:[0,1,3,4,7,9,10,14,16,17,19,27,29,30,32,33,34,35],make_ref:9,make_selected_refer:2,manag:[1,3,4,9,14,16,17,19,21],mandatori:14,mani:[0,4,11,17,21,28,29,33,35],manual:[13,34],map:4,mark:[0,2,6,9,27,30,32],mark_al:2,mark_count:6,mark_dup:2,mark_invert:2,mark_non:2,marker:0,markup:1,mash:7,mass:0,master:[1,27,30,35],match:[0,2,4,9,14,19,26,27,28,31,34],match_percentag:27,match_similar_word:4,matcher:29,matter:35,max:[21,26],max_progress:21,max_valu:26,mayb:[0,17],md5:[5,35],me6:1,mean:[0,1,7,13,14,17,19,24,28,31,33,34,35],meaning:19,meant:27,measur:34,mechan:[17,18,27],media:0,member:[27,28],memori:[0,4,26],memoryerror:26,menu:[0,14,29,30,31,33],menu_item:14,mercuri:10,merg:[0,1,4],merge_similar_word:4,mess:21,messag:[0,2,6,24],meta:[2,8],metadata:5,metho:2,method:[2,4,13,14,17,18,19,24,26,28,32,35],might:[0,1,11,15,17,26,27,28,34],min:[0,26],min_match_percentag:4,min_valu:26,mind:[1,7],minim:17,minimum:[0,4],minmax:26,minor:[0,1],minut:26,mirror:18,mishandl:0,miss:[1,4],mistakenli:0,mix:[6,16,31],modal:6,mode:[0,4,15,17,26,30,34,35],model:[13,14,16,17,18,30],modif:[1,28,34],modifi:[26,30,32,34,35],modified_aft:26,modul:[10,11,24],more:[0,1,2,4,14,17,19,21,25,26,27,29,30,31,33,34,35],moreov:[17,34],most:[1,13,17,28,29,34],mostli:[0,17,19,28],move:[0,2,5,11,14,19,30,31,34],move_column:14,mp3:0,msg:[6,24],mtime:26,much:[0,1,3,17,19,28,35],multi:35,multi_replac:26,multibind:13,multipl:[0,16,17,19,21,24,26,28,34,35],music:[0,4,28,29,30,35],must:[4,14,21,26,30,34,35],mydestin:31,myself:1,nah:0,naiv:35,name:[0,1,4,5,9,10,11,12,14,17,19,24,25,26,31,34,35],narrow:34,nasti:0,nation:35,natur:[1,17],necessari:4,need:[1,2,10,13,17,21,26,27,28,29,31,33,34],needlessli:35,nehyba:0,net:0,network:[28,34],never:[3,26,28,29,34],newer:1,newli:[17,34],newnam:2,newvalu:18,newwidth:14,next:[1,14,21,28,34],nice:31,no_field_ord:4,node:19,non:[0,18,26,27,30,34],none:[3,4,5,6,9,10,12,13,14,15,16,17,19,21,26],nonexist:1,nonon:26,nope:30,normal:[1,3,4,9,15,17,28,29,34,35],note:[6,16,21,34,35],noth:[0,1,13,14,16,17,18,19,21,28,35],notic:[0,30],notif:[2,24],notifi:[2,20,27],now:[0,1],nstableview:[7,13],nulljob:[3,4,9,21],number:[0,1,4,6,11,14,17,26,27,31,33,35],numer:[0,34],object:[0,2,3,4,9,13,14,21,24,26],obsolet:0,obtain:26,obvious:34,occasion:0,occur:[0,9,26],occurr:[16,26],ocurr:35,offer:[6,28],often:[4,13,14,18,19,24,35],ohanyan:0,old:[1,18,21],onc:[0,1,2,13,21,32,35],one:[0,2,4,13,14,18,21,24,26,27,28,29,33,34,35],ones:34,onli:[0,1,2,4,6,9,10,13,14,15,16,17,18,19,24,26,27,28,29,30,31,32,33,35],open:[0,1,2,12,26,28,29,34,35],open_if_filenam:26,open_path:12,open_select:2,open_url:12,oper:[0,5,6,17,27,28,31,35],operationerror:5,opportun:1,optim:35,option:[0,6,14,28,29,30,31,33,35],orang:[7,34],order:[0,2,4,14,17,26,28,33,34,35],ordered_column:14,ordered_index:14,organ:17,origin:34,oserror:25,osx:34,other:[1,2,4,6,17,25,26,28,29,34,35],other_nam:11,otherarg:25,otherwis:[26,35],our:[2,6,10,13,14,15,16,17,18,19,21,24,35],out:[1,4,10,16,19,26,34,35],outfil:[3,9],outfilenam:10,outlin:14,outsid:1,over:[17,26,27,28,32,34],overlap:26,overrid:[12,13,16,17,18],overriden:17,overwrit:0,own:[1,28,30],packag:[0,10],packages_nam:10,page:[27,30,34],pair:4,pane:35,panel:[0,29,31,34],paolo:0,paramet:[2,3,4,5,6,9,14,15,16,17,19,21,22],parent:[5,19,21,23,25],pars:[17,18],part:[0,4,26,34,35],particular:28,parton:35,pass:[15,21,26],past:1,patch:10,path:[0,2,3,5,9,10,12,19,20,26,27,31,34],pathifi:25,pattern:26,pavlov:0,peopl:1,per:2,percentag:[4,35],perform:[9,17,20,21,24,27,34,35],perform_on_mark:9,permiss:[0,28],permissionerror:0,persist:[2,14],petrashko:0,phan:0,phase:[0,35],photo:28,pick:33,pictur:[0,27,29,30,31],piec:27,pkgname:10,place:[0,14,17,27,31,34],placehold:[2,31],plai:[19,33,34],platform:[6,14,27,28],pleas:1,plural:26,plural_word:26,point:[9,16,33],pointer:3,polici:35,polish:0,polyval:29,pop:[0,26,29],popup:29,posit:[0,2,4,9,17,28,29,33,34,35],possibl:[0,1,4,17,31,35],post:[0,28,34],power:[0,27,28,29,33,34],practic:[1,17],preciou:1,precis:10,predic:[19,26],predict:0,pref:[0,2],prefaccess:14,prefaccessinterfac:14,prefer:[0,1,14,29,30,32,34,35],prefix:[14,17],preformat:7,prepar:17,prepend:[11,26,31],present:[0,2,3,6,16,17,34],preserv:[17,26],press:[6,28,34],pretti:[0,19,21],prev_el:26,prevent:[0,1,28,34],previou:[0,17],previous:[17,33],previous_select:17,principl:[17,30],print:10,print_and_do:10,priorit:[0,2,4,30],prioriti:34,privileg:34,probabl:[1,6,14,16,28],problem:[0,1,9,28,34,35],problemat:9,proce:[34,35],proceed:[6,26,34],process:[0,4,10,12,21,29,30,31,32],program:31,programmat:14,progress:[0,4,9,15,19,21,22,23,27],progress_window:[20,27],progressbar:15,progressdesc_textfield:15,progresswindow:15,progresswindowview:15,project:1,promot:[2,28,34],prompt:[6,13,29,34],propag:0,proper:[1,17],properli:[1,14,15],properti:[13,16,17,18],propos:1,proprietari:1,protocol:13,proxi:2,puls:15,punctuat:35,purge_ignore_list:2,purpos:[6,14,15,16,17,18],put:[0,1,2,10,15,17,18],py2app:10,pyqt:[0,27],python:[0,4,10,17,27,35],pythonpath:10,qtableview:[7,13],quadrat:35,queri:31,question:[14,30],quick:[14,30],quickli:[10,32,34],quicklook:0,quit:[0,10,17,19,27,35],quot:31,radio:6,rais:[3,9,15,16,17],ran:34,random:0,rang:[4,21],rather:[1,35],re_invalid_xml_sub:26,read:[0,10,17,30,32,34,35],readabl:17,readi:[5,7,17,27,29],readm:1,real:34,realli:[0,30,34],realm:1,reason:[28,34],receiv:[15,24],recent:[0,29],recommend:[15,34],record:4,recreat:31,recurs:[3,11,19,26,35],recycl:[0,32,34],reduc:0,reduce_common_word:4,ref:[0,2,4,9,31],refactor:0,refer:[0,1,2,3,4,6,13,14,17,29,30,31,32,33,34],refil:17,refresh:[0,13,15,16,17,18],refresh_view:17,regardless:[4,17],regarless:4,regexp:[9,34],regist:4,registr:0,regular:[0,31,34],regularli:15,rel:[31,34],relat:[0,15,19,29],releas:[0,1,27],relev:[0,1,6,12,17,28],reliabl:[0,10],reload:0,rem_file_ext:26,remain:35,rememb:[0,14],remind:0,remix:[30,35],remov:[0,2,3,4,9,16,17,21,26,27,29,30,31,32,34,35],remove_directori:2,remove_dupl:[2,9,27],remove_from_result:9,remove_mark:2,remove_select:2,removeselect:27,renam:[0,2,34],rename_select:2,reorder:4,repeat:24,repl:26,replac:[0,2,6,10,26,31,34,35],replace_from:26,replace_to:26,replace_valu:26,repo:27,report:[0,1,15,30],repositori:1,repres:[1,4,5,16,17,18,25,27],represent:[13,18],reprioritize_group:2,request:1,requir:[0,13,14,17,18,19],rerais:22,reraise_if_error:22,reset:[0,14],reset_to_default:14,resize_column:14,resolut:11,respect:[2,9,17,27,34],respond:[14,15],respons:[0,15,26],rest:[1,32],restor:[0,14,17],restore_column:14,result:[0,2,4,7,8,10,12,17,26,27,28,29,30,32,33,35],result_t:2,resultt:7,retriev:[3,14,18],revamp:0,reveal:[0,34],reveal_path:12,revers:[9,17,26,28],revert:17,review:30,rewrit:0,rgb:35,right:[0,14,21,27,28,31,33,34],rightmost:33,rigid:28,roadmap:1,role:[17,27],roman:0,root:[1,2,19,31],rossi:0,round:0,row:[7,16,17,34],row_count:17,row_index:17,rule:[10,26],run:[0,2,4,12,14,15,22,27,28,34],run_thread:22,russian:[0,30],safe:30,safeguard:13,sai:4,said:[1,18],same:[0,1,2,4,11,14,17,19,24,25,26,28,29,31,33,34,35],save:[0,2,3,9,14,17],save_a:2,save_column:14,save_edit:[14,17],save_to_fil:3,save_to_xml:9,savenam:14,scan:[0,2,3,4,5,27,30,31,32,34],scanner:[0,28],scatter:27,scope:[31,34],score:[4,35],screen:0,scroll:34,search:[26,30,34],second:[4,17,26,30,33,35],second_path:26,secondfil:27,section:30,secur:[28,34],see:[4,17,19,28,29,31,34],seek:0,seem:[2,17],seldom:0,select:[0,2,3,4,7,16,17,19,27,28,30,31,32,33],selectable_list:[20,27],selectablelist:[16,17],selected_dup:2,selected_index:[16,17],selected_nod:19,selected_path:19,selected_row:17,selector:29,self:[3,5,9,13,19,22,25],send:[0,2,6,15,17,30,32,34],sens:[4,16],sensibl:0,sent:[0,2,15,17,31],separ:[0,4,15,26,27,35],seq:26,sequenc:[16,17,19,21,26],seriou:1,session:2,set:[0,2,3,4,6,13,14,15,16,17,18,19,21,26,28,29,34],set_cell_valu:17,set_column_ord:14,set_column_vis:14,set_default:14,set_default_width:14,set_hardlink_option_en:6,set_progress:[15,21],set_stat:3,setattr:17,settabl:17,seven:35,sever:32,shaft:26,shallow:2,share:28,sharewar:1,shell:10,shelv:0,shift:34,shortcut:[17,34],shortest:0,should:[1,3,17,27,31,33],should_close_flag:26,shouldclos:26,show:[0,2,5,6,14,15,30],showdesc:26,shown:[2,26,29,34],side:[0,14,27,35],sierra:0,sifnific:4,sign:28,signific:[4,27],significantli:[0,35],similar:[0,4,17,29,31],simpl:[13,17,24,34],simpler:[17,19,35],simpli:[0,19,26,35],simplifi:0,sinc:[0,1,34,35],singl:[1,16,27],situat:[0,1,26],size:[0,5,26,28,33,34,35],skill:1,skipfirst:26,skipjob:21,slice:17,slider:30,slightli:35,slow:30,slower:[17,35],small:[0,35],smaller:[21,35],smart_copi:11,smart_mov:11,smartest:4,smartli:0,soft:0,softwar:[0,1,28],some:[0,1,2,3,4,13,14,15,16,17,28,35],some_work_func:22,somefil:31,somefold:31,someth:[1,2,17,18,21,28,34],sometim:[0,13,33,35],somewhat:19,song:[4,30,35],soon:[13,17,35],sort:[0,2,3,4,7,9,14,16,17,27,28,33,34],sort_bi:17,sort_dup:9,sort_group:9,sort_kei:2,sort_key_for_column:17,sortabl:17,sourc:[1,10,31,34,35],source_path:11,space:[28,31,34,35],spanish:0,sparkl:0,special:[12,29,30,35],special_fold:12,special_folder_path:12,specialfold:12,specif:[13,27,30],specifi:[15,16,21,26],speed:0,spend:1,sphinx:[0,1],split:[21,35],spot:34,spuriou:10,squar:28,stabl:[1,27],stai:[17,34],stall:0,stand:35,standard:[0,28,29,30,32,34,35],start:[0,1,2,3,13,15,17,19,21,26,27,29,30,31,34,35],start_edit:17,start_job:21,start_scan:[2,27],start_subjob:21,start_with:26,startup:[0,2],state:[0,2,3,6,28,30,34],statement:26,statu:[0,2,14,15,16,30],step:17,sticki:0,still:[1,28,34,35],stop:[0,1,3,17,21],stop_edit:17,storag:[14,17,28,34],store:[14,17,18,19,28],str:[2,6,9,14,18,25,26],string:[4,9,17,18,26,34,35],strip:26,stripe:35,stripfals:26,stuck:0,stuff:[10,17],sub:[4,21],subargu:33,subclass:[13,14,15,16,17,18,19,25,27],subfold:[0,3,29,31,35],subitem:5,subjob:21,sublass:13,subpath:25,subsequ:0,subset:34,suffix:[17,26],suggest:[30,35],sum:[5,35],summon:33,superdiffprog:31,suppli:19,support:[0,6,14,15,16,17,28,29,34],supports_link:6,suppos:[7,13,17,21],sure:[0,1,3,10,17,28,29,32,34],surrog:0,switch_ref:4,symlink:[0,6,34],sync:[0,16,17,18],sys:10,system:[0,24,28],systemat:0,tabl:[0,2,13,14,16,20,27],tag:[1,28,29,30,31,35],take:[1,2,4,7,9,15,16,17,19,26,27,28,30,34,35],taken:[26,34],target:[3,15],target_nod:19,task:[15,30,35],technic:[0,14,35],tell:[0,7,17,30],temporarili:0,tend:19,termin:15,test:10,testdata:10,text:[0,18,34],text_field:[20,27],textfield:[15,18],textfieldview:18,textual:15,than:[0,1,2,3,6,14,17,21,26,27,29,30,34,35],thei:[2,14,17,19,28,31,34,35],them:[0,1,3,4,7,14,17,21,25,26,28,29,31,32,34,35],themselv:2,therefor:[0,34,35],thi:[0,1,2,3,4,5,6,9,10,11,12,13,14,15,16,17,18,19,21,22,24,26,27,29,30,31,32,33,34,35],thin:[16,19],thing:[1,17,24,26,27,34],think:[1,15,28],thoroughli:1,those:[2,19,34,35],thought:1,thread:[0,15,22,27],threadedjobperform:[15,22,27],three:[28,29,30],threshold:[0,4,28,31,35],through:[0,3,17,18,21,27,31,33,35],thu:[1,16,28,29,34,35],tie:33,tie_break:4,ties:33,tiger:0,tight:26,tile:35,time:[1,13,14,15,17,19,21,27,28,34,35],timestamp:30,titl:[4,14,15,35],to_escap:26,togeth:[2,4,11,27,28,34],toggl:[6,14,34],toggle_menu_item:14,toler:4,too:[0,19,35],tool:[28,30],toolkit:[7,13,14,15,16,17,18,19],top:[4,10,28,34],topic:27,total:35,touch:[2,34],tox:27,track:[17,22,28],tracker:1,trailit:26,transform:26,translat:[1,26],trash:[0,2,6,30,34],treat:31,tree:[14,20,27],tri:[17,26,30,33,35],trick:33,trickier:1,trigger:18,trim:31,trivial:27,troubl:28,troubleshoot:34,trust:2,tryint:26,tune:29,tupl:[4,25],turn:[34,35],tweak:[0,32],two:[4,13,15,31,33,35],type:[0,3,6,13,17,18,28,30,31,34,35],typic:13,typo:0,ubuntu:0,ukrainian:[0,30],under:[0,3,12,14,34],underscor:17,understand:27,unfilt:34,unformat:17,unhandl:15,unicod:0,unicodeencodeerror:0,uniqu:11,unit:21,univers:0,unless:[29,34],unlik:35,unmaintain:0,unmark:2,unord:4,unpaid:0,unsav:0,unset:[13,14,18,19],until:[1,19,27,32],unveil:34,updat:[0,2,6,13,14,15,16,17,18,30],update_msg:6,update_select:16,upgrad:0,upon:0,url:12,usabl:19,usag:[0,26],use:[11,13,14,15,17,19,24,26,29,30,34,35],use_hardlink:6,use_regexp:0,used:[0,2,4,5,6,9,12,14,15,16,17,18,19,21,26,30,31,33,34,35],useful:[0,1,26,31],useless:10,user:[0,1,2,3,6,14,15,16,17,18,30,31],using:[0,1,9,28,31,32,34],usual:[14,15,17],util:[20,27],valu:[0,4,5,6,9,14,15,16,17,18,19,26,28,30,31,33,35],valueerror:16,variabl:10,variou:0,veri:[0,1,2,4,17,24,27,28,31,34,35],verifi:[31,32],version:[0,1,10,18,27,30],victor:0,vietnames:0,view:[2,6,13,14,15,16,17,18,19,30],virgil:1,virtual:[13,14,16,17,18,19],visibl:[2,14,34],vista:[0,34],visual:0,volum:10,wai:[0,1,2,4,6,7,10,17,18,28,29,34,35],wait:32,want:[0,1,2,13,15,16,17,18,19,21,26,29,30,34,35],warn:[0,21,35],wasn:[0,25],watch:35,weber:0,weight:[0,31],weight_word:4,well:[0,14,31,34,35],were:[0,17,33],what:[1,13,17,26,27,30,31,34],whatev:[1,17,34],whatnot:17,wheat:26,when:[0,1,2,3,4,6,9,11,13,14,15,16,17,18,19,21,25,27,28,29,31,33,34,35],whenev:[2,16,17,18,24],where:[0,1,4,13,16,17,19,21,26,27,30,33,34],whether:[1,3,5,6,11,14,17,19,25,26,34],which:[0,2,4,6,7,9,11,13,14,15,17,18,19,27,30,33,34,35],white:35,whitnei:35,who:1,whole:[0,4,13,14,17,18,19,34,35],whose:2,why:[2,6,13,14,27,30,34,35],wide:35,widget:[6,16,17,18],width:14,wikipedia:34,wildcard:34,win:33,window:[0,15,28,29,34],windowserror:25,wise:19,wish:1,with_dup:4,with_hour:26,within:[1,2,4],without:[2,4,9,10,11,17,26,27,29,30,31,34],without_ref:2,woe:0,won:[29,30],wonder:0,word:[0,2,4,26,30,31],word_dict:4,work:[0,1,5,17,19,21,22,25,28,31,34,35],workabl:19,worth:[4,35],would:[0,1,4,16,17,21,26,28,31,34,35],wouldn:[0,1,35],wrap:[3,5,9],wrapper:[5,16],writabl:0,write:[10,28,31],written:[1,28],wrong:[0,33],www:0,xhtml:[0,2,34],xml:[2,3,9],yaml:10,yeah:0,yet:17,yield:[15,19,26,35],you:[0,1,2,4,9,10,11,12,13,14,15,17,18,19,21,26,27,28,29,30,31,32,33,34,35],your:[0,1,13,15,16,17,19,21,22,28,29,30,31,32,33,34,35],yuri:0},titles:["Changelog","Contribute to dupeGuru","core.app","core.directories","core.engine","core.fs","core.gui.deletion_options","core.gui","core","core.results","hscommon.build","hscommon.conflict","hscommon.desktop","hscommon.gui.base","hscommon.gui.column","hscommon.gui.progress_window","hscommon.gui.selectable_list","hscommon.gui.table","hscommon.gui.text_field","hscommon.gui.tree","hscommon","hscommon.jobprogress.job","hscommon.jobprogress.performer","hscommon.jobprogress.qt","hscommon.notify","hscommon.path","hscommon.util","Developer Guide","Frequently Asked Questions","Folder Selection","dupeGuru help","Preferences","Quick Start","Re-Prioritizing duplicates","Results","The scanning process"],titleterms:{The:[28,35],about:34,action:34,all:28,api:27,app:2,applic:29,ask:28,awai:28,bar:28,base:13,bitrat:28,block:35,box:28,branch:27,bug:28,build:10,can:28,changelog:0,column:14,conflict:11,contain:28,content:[28,34,35],contribut:1,control:27,copi:28,core:[2,3,4,5,6,7,8,9,27],count:28,delet:[28,34],deletion_opt:6,delta:34,desktop:12,develop:[1,27],directori:3,disabl:28,discard:28,don:28,dupe:34,dupeguru:[1,7,28,30],duplic:[28,33,34],element:7,engin:4,exif:35,featur:28,field:[4,35],file:28,filter:[28,34],folder:[28,29,35],frequent:28,from:28,group:34,gui:[6,7,13,14,15,16,17,18,19],guid:27,hard:28,have:28,help:30,highest:28,how:28,hscommon:[10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26],indic:30,job:[21,27],jobprogress:[21,22,23],latest:28,list:29,live:28,locat:28,make:28,mark:[28,34],match:35,menu:34,meta:7,mode:[28,29],model:27,modifi:28,more:28,move:28,must:28,non:1,nope:27,notic:28,notifi:24,onli:34,option:34,path:25,perform:22,pictur:[28,35],prefer:[28,31],principl:27,priorit:33,process:[1,35],progress_window:15,question:28,quick:32,realli:28,refer:28,remix:28,remov:28,report:28,result:[9,34],review:34,safe:28,scan:[28,29,35],second:28,select:[29,34],selectable_list:16,send:28,show:34,similar:35,slider:28,slow:28,song:28,special:28,specif:28,start:32,state:29,statu:28,suggest:28,tabl:[17,30],tag:27,task:1,tell:28,text_field:18,than:28,thi:28,timestamp:35,trash:28,tree:19,tri:28,type:29,use:28,user:28,util:26,valu:34,version:28,view:27,want:28,weight:35,what:28,where:28,which:28,why:28,won:28,word:[28,35]}}) \ No newline at end of file diff --git a/help/fr/.buildinfo b/help/fr/.buildinfo new file mode 100644 index 00000000..7cde57d4 --- /dev/null +++ b/help/fr/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: ec529003170552bde5bf104aba0f5826 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/help/fr/.doctrees/changelog.doctree b/help/fr/.doctrees/changelog.doctree new file mode 100644 index 00000000..8ba5ced5 Binary files /dev/null and b/help/fr/.doctrees/changelog.doctree differ diff --git a/help/fr/.doctrees/environment.pickle b/help/fr/.doctrees/environment.pickle new file mode 100644 index 00000000..3e64bfd8 Binary files /dev/null and b/help/fr/.doctrees/environment.pickle differ diff --git a/help/fr/.doctrees/faq.doctree b/help/fr/.doctrees/faq.doctree new file mode 100644 index 00000000..c131d904 Binary files /dev/null and b/help/fr/.doctrees/faq.doctree differ diff --git a/help/fr/.doctrees/folders.doctree b/help/fr/.doctrees/folders.doctree new file mode 100644 index 00000000..dd73c768 Binary files /dev/null and b/help/fr/.doctrees/folders.doctree differ diff --git a/help/fr/.doctrees/index.doctree b/help/fr/.doctrees/index.doctree new file mode 100644 index 00000000..77f8073c Binary files /dev/null and b/help/fr/.doctrees/index.doctree differ diff --git a/help/fr/.doctrees/preferences.doctree b/help/fr/.doctrees/preferences.doctree new file mode 100644 index 00000000..0ef333c7 Binary files /dev/null and b/help/fr/.doctrees/preferences.doctree differ diff --git a/help/fr/.doctrees/quick_start.doctree b/help/fr/.doctrees/quick_start.doctree new file mode 100644 index 00000000..387aeb5e Binary files /dev/null and b/help/fr/.doctrees/quick_start.doctree differ diff --git a/help/fr/.doctrees/reprioritize.doctree b/help/fr/.doctrees/reprioritize.doctree new file mode 100644 index 00000000..d99e3ad4 Binary files /dev/null and b/help/fr/.doctrees/reprioritize.doctree differ diff --git a/help/fr/.doctrees/results.doctree b/help/fr/.doctrees/results.doctree new file mode 100644 index 00000000..5ac099db Binary files /dev/null and b/help/fr/.doctrees/results.doctree differ diff --git a/help/fr/_sources/changelog.rst.txt b/help/fr/_sources/changelog.rst.txt new file mode 100644 index 00000000..b1fc6f65 --- /dev/null +++ b/help/fr/_sources/changelog.rst.txt @@ -0,0 +1,705 @@ +:tocdepth: 1 + +Changelog +========= + +**About the word "crash":** When reading this changelog, you might be alarmed at the number of fixes +for "crashes". Be aware that when the word "crash" is used here, it refers to "soft crashes" which +don't cause the application to quit. You simply get an error window that asks you if you want to +send the crash report to Hardcoded Software. Crashes that cause the application to quit are called +"hard crashes" in this changelog. + + +4.0.3 (2016-11-24) +---------------------- + +* Add new picture cache backend: shelve +* Make shelve picture cache backend the active one on MacOS to fix `#394 `__ more + elegantly. [cocoa] +* Remove Sparkle (auto-updates) due to technical limitations. [cocoa] + + +4.0.2 (2016-10-09) +---------------------- + +* Fix systematic crash in Picture Mode under MacOS Sierra. (`#394 `__) +* No change for Linux. Just keeping version in sync. + + +4.0.1 (2016-08-24) +---------------------- + +* Add Greek localization, by Gabriel Koutilellis. (`#382 `__) +* Fix localization base path. [qt] (`#378 `__) +* Fix broken load results dialog. [qt] +* Fix crash on load results. [cocoa] (`#380 `__) +* Save preferences more predictably. [qt] (`#379 `__) +* Fix picture mode's fuzzy block scanner threshold. (`#387 `__) + + +4.0.0 (2016-07-01) +---------------------- + +* Merge Standard, Music and Picture editions in the same application! +* Improve documentation. (`#294 `__) +* Add Polish, Korean, Spanish and Dutch localizations. +* qt: Fix wrong use_regexp option propagation to core. (`#295 `__) +* qt: Fix progress window mistakenly showing up on startup. (`#357 `__) +* Bump Python requirement to v3.4. +* Bump OS X requirement to 10.8 +* Drop Windows support, maybe temporarily. + `Details `__-11-01>`_ +* cocoa: Drop iPhoto, Aperture and iTunes support. Was unmaintained and obsolete. +* Drop "Audio Contents" scan type. Was confusing and seldom useful. +* Change license to GPLv3 + + +3.9.1 (2014-10-17) +---------------------- + +* Fixed ``AttributeError: 'ComboboxModel' object has no attribute 'reset'``. [Linux, Windows] (`#254 `__) +* Fixed ``PermissionError`` on saving results. (`#266 `__) +* Fixed a build problem introduced by Sphinx 1.2.3. +* Updated German localisation, by Frank Weber. + + +3.9.0 (2014-04-19) +---------------------- + +* This is mostly a dependencies upgrade. +* Upgraded to Python 3.3. +* Upgraded to Qt 5. +* Minimum Windows version is now Windows 7 64bit. +* Minimum Ubuntu version is now 14.04. +* Minimum OS X version is now 10.7 (Lion). +* ... But with a couple of little improvements. +* Improved documentation. +* Overwrite subfolders' state when setting states in folder dialog (`#248 `__) +* The error report dialog now brings the user to Github issues. + + +3.8.0 (2013-12-07) +---------------------- + +* Disable symlink/hardlink deletion option when not relevant. (`#247 `__) +* Make Cmd+A select all folders in the Folder Selection dialog. [Mac] (`#228 `__) +* Make non-numeric delta comparison case insensitive. (`#239 `__) +* Fix surrogate-related UnicodeEncodeError on CSV export. (`#210 `__) +* Fixed crash on Dupe Count sorting with Delta + Dupes Only. (`#238 `__) +* Improved documentation. +* Important internal refactorings. +* Dropped Ubuntu 12.04 and 12.10 support. +* Removed the fairware dialog (`More Info `__). + + +3.7.1 (2013-08-19) +---------------------- + +* Fixed folder scan type, which was broken in v3.7.0. + + +3.7.0 (2013-08-17) +---------------------- + +* Improved delta values to support non-numerical values. (`#213 `__) +* Improved the Re-Prioritize dialog's UI. (`#224 `__) +* Added hardlink/symlink support on Windows Vista+. (`#220 `__) +* Dropped 32bit support on Mac OS X. +* Added Vietnamese localization by Phan Anh. + + +3.6.1 (2013-04-28) +---------------------- + +* Improved "Make Selection Reference" to make it clearer. (`#222 `__) +* Improved "Open Selected" to allow opening more than one file at once. (`#142 `__) +* Fixed a few typos here and there. (`#216 `__ `#225 `__) +* Tweaked the fairware dialog (`More Info `__). +* Added Arch Linux packaging +* Added a 64-bit build for Windows. +* Improved Russian localization by Kyrill Detinov. +* Improved Brazilian localization by Victor Figueiredo. + + +3.6.0 (2012-08-08) +---------------------- + +* Added "Export to CSV". (`#189 `__) +* Added "Replace with symlinks" to complement "Replace with hardlinks". [Mac, Linux] (`#194 `__) +* dupeGuru now tells how many duplicates were affected after each re-prioritization operation. (`#204 `__) +* Added Longest/Shortest filename criteria in the re-prioritize dialog. (`#198 `__) +* Fixed result table cells which mistakenly became writable in v3.5.0. [Mac] (`#203 `__) +* Fixed "Rename Selected" which was broken since v3.5.0. [Mac] (`#202 `__) +* Fixed a bug where "Reset to Defaults" in the Columns menu wouldn't refresh menu items' marked state. +* Added Brazilian localization by Victor Figueiredo. + + +3.5.0 (2012-06-01) +---------------------- + +* Added a Deletion Options panel. +* Greatly improved memory usage for big scans. +* Added a keybinding for the filter field. (`#182 `__) [Mac] +* Upgraded minimum requirements for Ubuntu to 12.04. + + +3.4.1 (2012-04-14) +---------------------- + +* Fixed the "Folders" scan type. [Mac] +* Fixed localization issues. [Windows, Linux] + + +3.4.0 (2012-03-29) +---------------------- + +* Improved results window UI. [Windows, Linux] +* Added a dialog to edit the Ignore List. +* Added the ability to sort results by "marked" status. +* Fixed "Open with default application". (`#190 `__) +* Fixed a bug where there would be a false reporting of discarded matches. (`#195 `__) +* Fixed various localization glitches. +* Fixed hard crashes on crash reporting. (`#196 `__) +* Fixed bug where the details panel would show up at inconvenient places in the screen. [Windows, Linux] + + +3.3.3 (2012-02-01) +---------------------- + +* Fixed crash on adding some folders. [Mac OS X] +* Added Ukrainian localization by Yuri Petrashko. + + +3.3.2 (2012-01-16) +---------------------- + +* Fixed random hard crashes (yeah, again). [Mac OS X] +* Fixed crash on Export to HTML. [Windows, Linux] +* Added Armenian localization by Hrant Ohanyan. +* Added Russian localization by Igor Pavlov. + + +3.3.1 (2011-12-02) +---------------------- + +* Fixed a couple of nasty crashes. + + +3.3.0 (2011-11-30) +---------------------- + +* Added multiple-selection in folder selection dialog for a more efficient folder removal. (`#179 `__) +* Fixed a crash in the prioritize dialog. (`#178 `__) +* Fixed a bug where mass marking with a filter would mark more than filtered duplicates. (`#181 `__) +* Fixed random hard crashes. [Mac OS X] (`#183 `__ `#184 `__) +* Added Czech localization by Aleš Nehyba. +* Added Italian localization by Paolo Rossi. + + +3.2.1 (2011-10-02) +---------------------- + +* Fixed a couple of broken action bindings from v3.2.0. + + +3.2.0 (2011-09-27) +---------------------- + +* Added duplicate re-prioritization dialog. (`#138 `__) +* Added font size preference for duplicate table. (`#82 `__) +* Added Quicklook support. [Mac OS X] (`#21 `__) +* Improved behavior of Mark Selected. (`#139 `__) +* Improved filename sorting. (`#169 `__) +* Added Chinese (Simplified) localization by Eric Dee. +* Tweaked the fairware system. +* Upgraded minimum requirements to OS X 10.6 and Ubuntu 11.04. + + +3.1.2 (2011-08-25) +---------------------- + +* Fixed a bug preventing the Folders scan from working. (`#172 `__) + + +3.1.1 (2011-08-24) +---------------------- + +* Added German localization by Gregor Tätzner. +* Improved OS X Lion compatibility. [Mac OS X] +* Made the file collection phase cancellable. (`#168 `__) +* Fixed glitch in folder window upon selecting a folder state. [Windows, Linux] (`#165 `__) +* Fixed a text coloring glitch in the results. (`#156 `__) +* Fixed glitch in the sorting feature of the Folder column. (`#161 `__) +* Make sure that saved results have the ".dupeguru" extension. [Linux] (`#157 `__) + + +3.1.0 (2011-04-16) +---------------------- + +* Added the "Folders" scan type. (`#89 `__) +* Fixed a couple of crashes. (`#140 `__ `#149 `__) + + +3.0.2 (2011-03-16) +---------------------- + +* Fixed crash after removing marked dupes. (`#140 `__) +* Fixed crash on error handling. [Windows] (`#144 `__) +* Fixed crash on copy/move. [Windows] (`#148 `__) +* Fixed crash when launching dupeGuru from a very long folder name. [Mac OS X] (`#119 `__) +* Fixed a refresh bug in directory panel. (`#153 `__) +* Improved reliability of the "Send to Trash" operation. [Linux] +* Tweaked Fairware reminders. + + +3.0.1 (2011-01-27) +---------------------- + +* Restored the context menu which had been broken in 3.0.0. [Mac OS X] (`#133 `__) +* Fixed a bug where an "unsaved results" warning would be issued on quit even with empty results. (`#134 `__) +* Removed focus from the cancel button in the progress dialog to avoid accidental cancellations. [Mac OS X] (`#135 `__) +* Folders added through drag and drop are added to the recent folders list. (`#136 `__) +* Added a debugging mode. (`#132 `__) +* Fixed french localization glitches. + + +3.0.0 (2011-01-24) +---------------------- + +* Re-designed the UI. (`#129 `__) +* Internationalized dupeGuru and localized it to french. (`#32 `__) +* Changed the format of the help file. (`#130 `__) + + +2.12.3 (2011-01-01) +---------------------- + +* Fixed bug causing results to be corrupted after a scan cancellation. (`#120 `__) +* Fixed crash when fetching Fairware unpaid hours. (`#121 `__) +* Fixed crash when replacing files with hardlinks. (`#122 `__) + + +2.12.2 (2010-10-05) +---------------------- + +* Fixed delta column colors which were broken since 2.12.0. +* Fixed column sorting crash. (`#108 `__) +* Fixed occasional crash during scan. (`#106 `__) + + +2.12.1 (2010-09-30) +---------------------- + +* Re-licensed dupeGuru to BSD and made it `Fairware `__. + + +2.12.0 (2010-09-26) +---------------------- + +* Improved UI with a little revamp. +* Added the possibility to place hardlinks to references after having deleted duplicates. [Mac OS X, Linux] (`#91 `__) +* Added an option to ignore duplicates hardlinking to the same file. [Mac OS X, Linux] (`#92 `__) +* Added multiple selection in the "Add Directory" dialog. [Mac OS X] (`#105 `__) +* Fixed a bug preventing drag & drop from working in the Directories panel. [Windows, Linux] + + +2.11.1 (2010-08-26) +---------------------- + +* Fixed HTML exporting which was broken in 2.11.0. + + +2.11.0 (2010-08-18) +---------------------- + +* Added the ability to save results (and reload them) at arbitrary locations. +* Improved the way reference files in dupe groups are chosen. (`#15 `__) +* Remember size/position of all windows between launches. (`#102 `__) +* Fixed a bug sometimes preventing dupeGuru from reloading previous results. +* Fixed a bug sometimes causing the progress dialog to be stuck there. [Mac OS X] (`#103 `__) +* Removed the Creation Date column, which wasn't displaying the correct value anyway. (`#101 `__) + + +2.10.1 (2010-07-15) +---------------------- + +* Fixed a couple of crashes. (`#95 `__, `#97 `__, `#100 `__) + + +2.10.0 (2010-04-13) +---------------------- + +* Improved error messages when files can't be sent to trash, moved or copied. +* Added a custom command invocation action. (`#12 `__) +* Filters are now applied on whole paths. (`#4 `__) + + +2.9.2 (2010-02-10) +---------------------- + +* dupeGuru is now 64-bit on Mac OS X! +* Fixed a crash upon quitting when support folder is not present. (`#83 `__) +* Fixed a crash during sorting. (`#85 `__) +* Fixed selection glitches, especially while renaming. (`#93 `__) + + +2.9.1 (2010-01-13) +---------------------- + +* Improved memory usage for Contents scans. (`#75 `__) +* Improved scanning speed when ref directories are involved. (`#77 `__) +* Show a message dialog at the end of the scan if no duplicates are found. (`#81 `__) +* Fixed a bug sometimes causing the small files threshold pref to be ignored. [Mac OS X] (`#75 `__) + + +2.9.0 (2009-11-03) +---------------------- + +* Significantly improved speed and memory usage of big contents-based scans. +* Added drag & drop support in the Directories panel. (`#9 `__) +* Fixed a bug causing dupeGuru to be confused if a scanned file was moved during the scan. (`#72 `__) +* Dropped support for Mac OS X 10.4 (Tiger) + + +2.8.2 (2009-10-14) +---------------------- + +* Improved directory selection in the Directories panel (Windows). (`#56 `__) +* Fixed a bug preventing dupeGuru from starting on certain machines (Windows). (`#68 `__) +* Fixed a crash during very big scans. (`#70 `__) + + +2.8.1 (2009-10-02) +---------------------- + +* Fixed crash with filtering when regular expressions were enabled. (`#60 `__) +* Fixed crash when setting directories' state. (Mac OS X) (`#66 `__) +* Fixed crash with Make Reference when certain filters are applied. (Mac OS X) (`#55 `__) +* Improved error handling during delete/move/copy actions. (`#62 `__ `#65 `__) + + +2.8.0 (2009-09-07) +---------------------- + +* Added support for all kinds of bundle (not just applications) (Mac OS X) (`#11 `__) +* Re-introduced the Export to XHTML feature to Windows. (`#14 `__) +* Improved Export to XHTML speed. (`#14 `__) +* Improved Contents scanning speed for large files. (`#33 `__) +* Improved the grouping algorithm to reduce the number of discarded files in non-exact scans. (`#51 `__) +* Stopped showing the same file on the 2 sides of the details panel when a ref file is selected. (`#50 `__) +* Fixed crashes in the Directories panel. (`#46 `__) + + +2.7.3 (2009-06-20) +---------------------- + +* Fixed bugs with selection being jumpy during "Make Reference" actions and Power Marker + switches. (`#3 `__) +* Fixed crash happening when a file with non-roman characters couldn't be analyzed. (`#30 `__) +* Fixed crash sometimes happening during the file collection phase in scanning. (`#38 `__) +* Restored double-click and right-click behavior lost in the PyQt move (Windows). (`#34 `__ `#35 `__) + + +2.7.2 (2009-06-10) +---------------------- + +* Fixed an occasional crash on Copy/Move operations. (`#16 `__) +* Added automatic exclusion for sensible folders (like system folders). (`#20 `__) +* Fixed an occasional crash when application files were part of the results (Mac OS X). (`#25 `__) + + +2.7.1 (2009-05-29) +---------------------- + +* Fixed a bug causing crashes when having application files in the results. +* Fixed a bug causing a GUI freeze at the beginning of a scan with a lot of files. +* Fixed a bug that sometimes caused a crash when an action was cancelled, and then started again. + + +2.7.0 (2009-05-25) +---------------------- + +* Converted the Windows GUI to Qt. +* Improved the reliability of the scanning process. + + +2.6.1 (2009-03-27) +---------------------- + +* **Fixed** an occasional crash caused by permission issues. +* **Fixed** a bug where the "X discarded" notice would show a too large number of discarded + duplicates. + + +2.6.0 (2008-09-10) +---------------------- + +* **Added** a small file threshold preference. +* **Added** a notice in the status bar when matches were discarded during the scan. +* **Improved** duplicate prioritization (smartly chooses which file you will keep). +* **Improved** scan progress feedback. +* **Improved** responsiveness of the user interface for certain actions. + + +2.5.4 (2008-08-10) +---------------------- + +* **Improved** the speed of results loading and saving. +* **Fixed** a crash sometimes occurring during duplicate deletion. + + +2.5.3 (2008-07-08) +---------------------- + +* **Improved** unicode handling for filenames. dupeGuru will now find a lot more duplicates if your files have non-ascii characters in it. +* **Fixed** "Clear Ignore List" crash in Windows. + + +2.5.2 (2008-01-10) +---------------------- + +* **Improved** the handling of low memory situations. +* **Improved** the directory panel. The "Remove" button changes to "Put Back" when an excluded directory is selected. +* **Improved** scan, delete and move speed in situations where there were a lot of duplicates. +* **Fixed** occasional crashes when moving bundles (such as .app files). +* **Fixed** occasional crashes when moving a lot of files at once. + + +2.5.1 (2007-11-22) +---------------------- + +* **Added** the "Remove empty folders" option. +* **Fixed** results load/save issues. +* **Fixed** occasional status bar inaccuracies when the results are filtered. + + +2.5.0 (2007-09-15) +---------------------- + +* **Added** post scan filtering. +* **Fixed** issues with the rename feature under Windows +* **Fixed** some user interface annoyances under Windows + + +2.4.8 (2007-04-14) +---------------------- + +* **Improved** UI responsiveness (using threads) under Mac OS X. +* **Improved** result load/save speed and memory usage. + + +2.4.7 (2007-03-10) +---------------------- + +* **Fixed** a "bad file descriptor" error occasionally popping up. +* **Fixed** a bug with non-latin directory names. + + +2.4.6 (2007-02-10) +---------------------- + +* **Added** Re-orderable columns. In fact, I re-added the feature which was lost in the C# conversion in 2.4.0 (Windows). +* **Changed** the behavior of the scanning engine when setting the hardness to 100. It will now only match files that have their words in the same order. +* **Fixed** a bug with all the Delete/Move/Copy actions with certain kinds of files. + + +2.4.5 (2007-01-11) +---------------------- + +* **Fixed** a bug with the Move action. + + +2.4.4 (2007-01-07) +---------------------- + +* **Fixed** a "ghosting" bug. Dupes deleted by dupeGuru would sometimes come back in subsequent scans (Windows). +* **Fixed** bugs sometimes making dupeGuru crash when marking a dupe (Windows). +* **Fixed** some minor visual glitches (Windows). + + +2.4.3 (2006-12-08) +---------------------- + +* **Fixed** a mishandling of ".app" files (OS X). +* **Fixed** a bug preventing files from "reference" directories to be displayed in blue in the results (Windows). +* **Fixed** a bug preventing some files to be sent to the recycle bin (Windows). +* **Fixed** a bug in the packaging preventing certain Windows configurations to start dupeGuru at all. + + +2.4.2 (2006-11-18) +---------------------- + +* **Fixed** a bug with directory states. + + +2.4.1 (2006-11-15) +---------------------- + +* **Fixed** a bug causing the ignore list not to be saved. +* **Fixed** a bug sometimes making delete and move operations stall. + + +2.4.0 (2006-11-10) +---------------------- + +* **Changed** the Windows interface. It is now .NET based. +* **Added** an auto-update feature to the windows version. +* **Changed** the way power marking works. It is now a mode instead of a separate window. +* **Changed** the "Size (MB)" column for a "Size (KB)" column. The values are now "ceiled" instead of rounded. Therefore, a size "0" is now really 0 bytes, not just a value too small to be rounded up. It is also the case for delta values. +* **Removed** the min word length/count options. These came from Mp3 Filter, and just aren't used anymore. Word weighting does pretty much the same job. + + +2.3.4 (2006-11-07) +---------------------- + +* **Improved** speed and memory usage of the scanning engine, again. Does it mean there was a lot of improvements to be made? Nah... + + +2.3.3 (2006-11-02) +---------------------- + +* **Improved** speed and memory usage of the scanning engine, especially when the scan results in a lot of duplicates. +* Now I wonder if Sparkle is going to work well... + + +2.3.2 (2006-10-16) +---------------------- + +* **Added** an auto-update feature in the Mac OS X version (with Sparkle). +* **Fixed** a bug preventing some duplicate reports to be created correctly under Windows. + + +2.3.1 (2006-10-02) +---------------------- + +* **Fixed** a bug preventing some duplicates to be found, especially when scanning lots of files. + + +2.3.0 (2006-09-22) +---------------------- + +* **Added** XHTML export feature. + + +2.2.10 (2006-08-31) +---------------------- + +* **Added** sticky columns. +* **Fixed** an issue with file caching between scans. +* **Fixed** an issue preventing some duplicates from being deleted/moved/copied. + + +2.2.9 (2006-08-27) +---------------------- + +* **Fixed** an issue with ignore list and unicode. +* **Fixed** an issue with file attribute fetching sometimes causing dupeGuru to crash. +* **Fixed** an issue in the directories panel under Windows. + + +2.2.8 (2006-08-17) +---------------------- + +* **Fixed** an issue in the duplicate seeking engine preventing some duplicates to be found. + + +2.2.7 (2006-08-12) +---------------------- + +* **Improved** unicode support. +* **Improved** the "Reveal in Finder" ("Open Containing Folder" in Windows) feature so it selects the file in the folder it opens. + + +2.2.6 (2006-08-07) +---------------------- + +* **Improved** the ignore list system. +* dupeGuru is now a Universal application on Mac OS X. + + +2.2.5 (2006-07-26) +---------------------- + +* **Improved** application (.app) dupe detection on Mac OS X. +* **Fixed** an issue that occasionally made dupeGuru crash on startup. + + +2.2.4 (2006-06-27) +---------------------- + +* **Fixed** an issue with Move and Copy features. + + +2.2.3 (2006-06-15) +---------------------- + +* **Improved** duplicate scanning speed. +* **Added** a warning that a file couldn't be renamed if a file with the same name already exists. + + +2.2.2 (2006-06-07) +---------------------- + +* **Added** "Rename Selected" feature. +* **Fixed** some minor issues with "Reload Last Results" feature. +* **Fixed** ignore list issues. + + +2.2.1 (2006-05-22) +---------------------- + +* **Fixed** occasional progress bar woes under Windows. +* **Fixed** a bug in the registration system under Windows. +* Nothing has been changed in the Mac OS X version, but I want to keep version in sync. + + +2.2.0 (2006-05-10) +---------------------- + +* **Added** destination path re-creation options. +* **Added** an ignore list. +* **Changed** the main icon. +* **Improved** dramatically the delta values feature. + + +2.1.2 (2006-04-18) +---------------------- + +* **Added** the "Match similar words" option. +* **Fixed** Power marking issues under Mac. + + +2.1.1 (2006-04-14) +---------------------- + +* **Added** the "Display delta values" option. +* **Improved** Power marking sorting speed under Mac. +* **Fixed** Power marking sorting issues. + + +2.1.0 (2006-04-03) +---------------------- + +* **Added** the Power Marker feature. +* **Fixed** a column sorting bug. The results would sometimes lose their sort order. +* **Fixed** a bug with the Make Reference feature. The results sometimes wasn't correctly refreshed after the reference switch. + + +2.0.1 (2006-03-23) +---------------------- + +* **Fixed** an issue occasionally occurring when trying to reload results from removable media that is no longer present. + + +2.0.0 (2006-03-17) +---------------------- + +* Complete rewrite. +* Now runs on Mac OS X. + + +1.0.0 (2004-09-24) +---------------------- + +* Initial release. + diff --git a/help/fr/_sources/faq.rst.txt b/help/fr/_sources/faq.rst.txt new file mode 100644 index 00000000..f8eae327 --- /dev/null +++ b/help/fr/_sources/faq.rst.txt @@ -0,0 +1,192 @@ +Foire aux questions +=================== + +.. contents:: + +Qu'est-ce que dupeGuru? +------------------------ + +.. only:: edition_se + + dupeGuru est un outil pour trouver des doublons parmi vos fichiers. Il peut comparer soit les + noms de fichiers, soit le contenu. Le comparateur de nom de fichier peut trouver des doublons + même si les noms ne sont pas exactement pareils. + +.. only:: edition_me + + dupeGuru Music Editon est un outil pour trouver des doublons parmi vos chansons. Il peut + comparer les noms de fichiers, les tags ou bien le contenu. Les comparaisons de nom de fichier + ou de tags peuvent trouver des doublons même si les noms de sont pas exactement pareils. + +.. only:: edition_pe + + dupeGuru Picture Edition est un outil pour trouver des doublons parmi vos images. Non seulement + il permet de trouver les doublons exactes, mais il est aussi capable de trouver les images ayant + de légères différences, étant de format différent ou bien ayant une qualité différente. + +En quoi est-il mieux que les autres applications? +------------------------------------------------- + +dupeGuru est hautement configurable. Vous pouvez changer les options de comparaison afin de trouver +exactement le type de doublons recherché. Plus de détails sur la +:doc:`page de préférences `. + +dupeGuru est-il sécuritaire? +---------------------------- + +Oui. dupeGuru a été conçu afin d'être certain que vous conserviez toujours au moins une copie des +doublons que vous trouvez. Il est aussi possible de configurer dupeGuru afin de déterminer certains +dossier à partir desquels aucun fichier ne sera effacé. + +Quelles sont les limitation démo de dupeGuru? +--------------------------------------------- + +En mode de démonstration, les actions sont limitées à 10 doublons par session. En mode `Fairware`_, +il n'y a pas de limitation. + +Je ne peux pas marquer le doublons que je veux effacer, pourquoi? +----------------------------------------------------------------- + +Tour groupe de doublons contient au moins un fichier dit "référence" et ce fichier ne peut pas être +effacé. Par contre, ce que vous pouvez faire c'est de le remplacer par un autre fichier du groupe. +Pour ce faire, sélectionnez un fichier du groupe et cliquez sur l'action **Transformer sélectionnés +en références**. + +Notez que si le fichier référence du groupe vient d'un dossier qui a été défini comme dossier +référence, ce fichier ne peut pas être déplacé de sa position de référence du groupe. + +J'ai un dossier duquel je ne veut jamais effacer de fichier. +------------------------------------------------------------ + +Si vous faites un scan avec un dossier qui ne doit servir que de référence pour effacer des doublons +dans un autre dossier, changez le type de dossier à "Référence" dans la fenêtre de +:doc:`sélection de dossiers `. + +Que veut dire '(X hors-groupe)' dans la barre de statut? +-------------------------------------------------------- + +Lors de certaines comparaisons, il est impossible de correctement grouper les paires de doublons et +certaines paires doivent être retirées des résultats pour être certain de ne pas effacer de faux +doublons. Example: Nous avons 3 fichiers, A, B et C. Nous les comparons en utilisant un petit seuil +de filtre. La comparaison détermine que A est un double de B, A est un double C, mais que B n'est +**pas** un double de C. dupeGuru a ici un problème. Il ne peut pas créer un groupe avec A, B et C. +Il décide donc de jeter C hors du groupe. C'est de là que vient la notice '(X hors-groupe)'. + +Cette notice veut dire que si jamais vous effacez tout les doubles contenus dans vos résultats et +que vous faites un nouveau scan, vous pourriez avoir de nouveaux résultats. + +Je veux marquer tous les fichiers provenant d'un certain dossier. Quoi faire? +----------------------------------------------------------------------------- + +Activez l'option :doc:`Ne pas montrer les références ` et cliquez sur la colonne Dossier +afin de trier par dossier. Il sera alors facile de sélectionner tous les fichiers de ce dossier +(avec Shift+selection) puis ensuite d'appuyer sur Espace pour marquer les fichiers sélectionnés. + +.. only:: edition_se or edition_pe + + Je veux enlever tous les doublons qui ont une différence de plus de 300KB avec leur référence. + ---------------------------------------------------------------------------------------------- + + * Activez l'option :doc:`Ne pas montrer les références `. + * Activez l'option **Montrer les valeurs en tant que delta**. + * Cliquez sur la colonne Taille pour changer le tri. + * Sélectionnez tous les fichiers en dessous de -300. + * Cliquez sur l'action **Retirer sélectionnés des résultats**. + * Sélectionnez tous les fichiers au dessus de 300. + * Cliquez sur l'action **Retirer sélectionnés des résultats**. + + Je veux que le fichier avec la plus grande date de dernière modification soit la référence. + ------------------------------------------------------------------------------------------- + + * Activez l'option :doc:`Ne pas montrer les références `. + * Activez l'option **Montrer les valeurs en tant que delta**. + * Cliquez sur la colonne Modification (deux fois, afin d'avoir un ordre descendant) pour changer le tri. + * Sélectionnez tous les fichiers au dessus de 0. + * Cliquez sur l'action **Transformer sélectionnés en références**. + + Je veux marquer tous les fichiers contenant le mot "copie". + ----------------------------------------------------------- + + * Entrez le mot "copie" dans le champ "Filtre" dans la fenêtre de résultats puis appuyez sur + Entrée. + * Cliquez sur **Tout Marquer** dans le menu Marquer. + +.. only:: edition_me + + Je veux enlever les doublons qui ont une différence de plus de 3 secondes avec leur référence. + ---------------------------------------------------------------------------------------------- + + * Activez l'option :doc:`Ne pas montrer les références `. + * Activez l'option **Montrer les valeurs en tant que delta**. + * Cliquez sur la colonne Temps pour changer le tri. + * Sélectionnez tous les fichiers en dessous de -00:03. + * Cliquez sur l'action **Retirer sélectionnés des résultats**. + * Sélectionnez tous les fichiers au dessus de 00:03. + * Cliquez sur l'action **Retirer sélectionnés des résultats**. + + Je veux que mes chansons aux bitrate le plus élevé soient mes références. + ------------------------------------------------------------------------- + + * Activez l'option :doc:`Ne pas montrer les références `. + * Activez l'option **Montrer les valeurs en tant que delta**. + * Cliquez sur la colonne Bitrate (deux fois, afin d'avoir un ordre descendant) pour changer le tri. + * Sélectionnez tous les fichiers au dessus de 0. + * Cliquez sur l'action **Transformer sélectionnés en références**. + + Je veux enlever les chansons contenant "[live]" ou "[remix]" de mes résultat. + ----------------------------------------------------------------------------- + + Si votre seuil de filtre est assez bas, il se pourrait que vos chansons live ou vos remix soient + détectés comme des doublons. Vous n'y pouvez rien, mais ce que vous pouvez faire est d'enlever + ces fichiers de vous résultats après le scan. Si, par exemple, vous voulez enlever tous les + doublons contenant quelque mot que ce soit entre des caractères "[]", faites: + + * Entrez "[*]" dans le champ "Filtre" dans la fenêtre de résultats puis appuyez sur Entrée. + * Cliquez sur **Tout Marquer** dans le menu Marquer. + * Cliquez sur l'action **Retirer marqués des résultats**. + +J'essaie d'envoyer mes doublons à la corbeille, mais dupeGuru me dit que je ne peux pas. Pourquoi? +-------------------------------------------------------------------------------------------------- + +La plupart du temps, la raison pour laquelle dupeGuru ne peut pas envoyer des fichiers à la +corbeille est un problème de permissions. Vous devez avoir une permission d'écrire dans les fichiers +que vous voulez effacer. Si vous n'êtes pas familiers avec la ligne de commande, vous pouvez +utiliser des outils comme `BatChmod`_ pour modifier vos permissions. + +Si malgré cela vous ne pouvez toujours pas envoyer vos fichiers à la corbeille, essayez l'option +"Supprimer les fichiers directement" qui vous est offerte lorsque vous procédez à l'effacement des +doublons. Cette option fera en sorte de supprimer directement les fichiers sans les faire passer par +la corbeille. Dans certains cas, ça règle le problème. + +.. only:: edition_pe + + Si vous essayez d'effacer des photos dans iPhoto, alors la raison du problème est différente. + L'opération rate parce que dupeGuru ne peut pas communiquer avec iPhoto. Il faut garder à + l'esprit qu'il ne faut pas toucher à iPhoto pendant l'opération parce que ça peut déranger la + communication entre dupeGuru et iPhoto. Aussi, quelque fois, dupeGuru ne peut pas trouver + l'application iPhoto. Il faut mieux alors démarrer iPhoto avant l'opération. + +Dans le pire des cas, `contactez le support HS`_, on trouvera bien. + +Où sont les fichiers de configuration de dupeGuru? +-------------------------------------------------- + +Si, pour une raison ou une autre, vous voulez effacer ou modifier les fichiers générés par dupeGuru, +voici où ils sont: + +* Linux: ``~/.local/share/data/Hardcoded Software/dupeGuru`` +* Mac OS X: ``~/Library/Application Support/dupeGuru`` +* Windows: ``\Users\\AppData\Local\Hardcoded Software\dupeGuru`` + +Les fichiers de préférences sont ailleurs: + +* Linux: ``~/.config/Hardcoded Software/dupeGuru.conf`` +* Mac OS X: Dans le système ``defaults`` sous ``com.hardcoded-software.dupeguru`` +* Windows: Dans le Registre, sous ``HKEY_CURRENT_USER\Software\Hardcoded Software\dupeGuru`` + +Pour la Music Edition et Picture Edition, remplacer "dupeGuru" par "dupeGuru Music Edition" et +"dupeGuru Picture Edition", respectivement. + +.. _Fairware: http://open.hardcoded.net/about/ +.. _BatChmod: http://www.lagentesoft.com/batchmod/index.html +.. _contactez le support HS: http://www.hardcoded.net/support diff --git a/help/fr/_sources/folders.rst.txt b/help/fr/_sources/folders.rst.txt new file mode 100644 index 00000000..54acf952 --- /dev/null +++ b/help/fr/_sources/folders.rst.txt @@ -0,0 +1,57 @@ +Sélection de dossiers +===================== + +La première fenêtre qui apparaît lorsque dupeGuru démarre est la fenêtre de sélection de dossiers à scanner. Elle détermine la liste des dossiers qui seront scannés lorsque vous cliquerez sur **Scan**. + +Pour ajouter un dossier, cliquez sur le bouton **+**. Si vous avez ajouté des dossiers dans le passé, un menu vous permettra de rapidement choisir un de ceux ci. Autrement, il vous sera demandé d'indiquer le dossier à ajouter. + +Vous pouvez aussi utiliser le drag & drop pour ajouter des dossiers à la liste. + +Pour retirer un dossier, sélectionnez le et cliquez sur **-**. Si le dossier sélectionné est un sous-dossier, son type changera pour **exclus** (voyez plus bas) au lieu d'être retiré. + +Types de dossiers +----------------- + +Tout dossier ajouté à la liste est d'un type parmis ces trois: + +* **Normal:** Les doublons trouvés dans ce dossier peuvent être effacés. +* **Reference:** Les doublons trouvés dans ce dossier ne peuvent **pas** être effacés. Les fichiers provenant de ce dossier ne peuvent qu'être en position "Référence" dans le groupes de doublons. +* **Excluded:** Les fichiers provenant de ce dossier ne sont pas scannés. + +Le type par défaut pour un dossier est, bien entendu, **Normal**. Vous pouvez utiliser le type **Référence** pour les dossiers desquels vous ne voulez pas effacer de fichiers. + +Le type d'un dossier s'applique à ses sous-dossiers, excepté si un sous-dossier a un autre type explicitement défini. + +.. only:: edition_pe + + Bibliothèques iPhoto et Aperture + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + dupeGuru PE supporte iPhoto et Aperture, ce qui veut dire qu'il sait comment lire le contenu de + ces bibliothèques et comment communiquer avec ces applications pour correctement supprimer des + photos de celles-ci. Pour utiliser cette fonctionnalité, vous devez ajouter iPhoto et/ou + Aperture avec les boutons spéciaux "Ajouter librairie iPhoto" et "Ajouter librairie Aperture", + qui apparaissent quand on clique sur le petit "+". Les dossiers ajoutés seront alors + correctement interprétés par dupeGuru. + + Quand une photo est supprimée d'iPhoto, elle est envoyée dans la corbeille d'iPhoto. + + Quand une photo est supprimée d'Aperture, il n'est malheureusement pas possible de l'envoyer + dans sa corbeille. Ce que dupeGuru fait à la place, c'est de créer un projet "dupeGuru Trash" + et d'envoyer les photos dans ce projet. Vous pouvez alors supprimer toutes les photos de ce + projet manuellement. + +.. only:: edition_me + + Bibliothèques iTunes + ^^^^^^^^^^^^^^^^^^^^ + + dupeGuru ME supporte iTunes, ce qui veut dire qu'il sait comment lire le contenu de sa + bibliothèque et comment communiquer avec iTunes pour correctement supprimer des chansons de sa + bibliothèque. Pour utiliser cette fonctionnalité, vous devez ajouter iTunes avec le bouton + spécial "Ajouter librairie iTunes", qui apparait quand on clique sur le petit "+". Le dossier + ajouté sera alors correctement interprété par dupeGuru. + + Quand une chanson est supprimée d'iTunes, elle est envoyée à la corebeille du système, comme un + fichier normal. La différence ici, c'est qu'après la suppression, iTunes est correctement mis au + fait de cette suppression et retire sa référence à cette chanson de sa bibliothèque. diff --git a/help/fr/_sources/index.rst.txt b/help/fr/_sources/index.rst.txt new file mode 100644 index 00000000..c80023c1 --- /dev/null +++ b/help/fr/_sources/index.rst.txt @@ -0,0 +1,47 @@ +Aide dupeGuru +=============== + +.. only:: edition_se + + Ce document est aussi disponible en `anglais `__, en `allemand `__ et en `arménien `__. + +.. only:: edition_me + + Ce document est aussi disponible en `anglais `__, en `allemand `__ et en `arménien `__. + +.. only:: edition_pe + + Ce document est aussi disponible en `anglais `__, en `allemand `__ et en `arménien `__. + +.. only:: edition_se or edition_me + + dupeGuru est un outil pour trouver des doublons parmi vos fichiers. Il peut comparer soit les noms de fichiers, soit le contenu. Le comparateur de nom de fichier peut trouver des doublons même si les noms ne sont pas exactement pareils. + +.. only:: edition_pe + + dupeGuru Picture Edition est un outil pour trouver des doublons parmi vos images. Non seulement il permet de trouver les doublons exactes, mais il est aussi capable de trouver les images ayant de légères différences, étant de format différent ou bien ayant une qualité différente. + +Bien que dupeGuru puisse être utilisé sans lire l'aide, une telle lecture vous permettra de bien comprendre comment l'application fonctionne. Pour un guide rapide pour une première utilisation, référez vous à la section :doc:`Démarrage Rapide `. + +C'est toujours une bonne idée de garder dupeGuru à jour. Vous pouvez télécharger la dernière version sur sa `homepage`_. + +Contents: + +.. toctree:: + :maxdepth: 2 + + quick_start + folders + preferences + results + reprioritize + faq + changelog + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` + +.. _homepage: https://www.hardcoded.net/dupeguru \ No newline at end of file diff --git a/help/fr/_sources/preferences.rst.txt b/help/fr/_sources/preferences.rst.txt new file mode 100644 index 00000000..25811581 --- /dev/null +++ b/help/fr/_sources/preferences.rst.txt @@ -0,0 +1,63 @@ +Préférences +=========== + +.. only:: edition_se + + **Type de scan:** Cette option détermine quels aspects du fichier doit être comparé. Un scan par **Nom de fichier** compare les noms de fichiers mot-à-mot et, dépendant des autres préférences ci-dessous, déterminera si les noms se ressemblent assez pour être considérés comme doublons. Un scan par **Contenu** trouvera les doublons qui ont exactement le même contenu. + + Le scan **Dossiers** est spécial. Si vous le sélectionnez, dupeGuru cherchera des doublons de *dossiers* plutôt que des doublons de fichiers. Pour déterminer si deux dossiers sont des doublons, dupeGuru regarde le contenu de tous les fichiers dans les dossiers, et si **tous** sont les mêmes, les dossiers sont considérés comme des doublons. + + **Seuil du filtre:** Pour les scan de type **Nom de fichier**, cette option détermine le degré de similtude nécessaire afin de considérer deux noms comme doublons. Avec un seuil de 80, 80% des mots doivent être égaux. Pour déterminer ce pourcentage, dupeGuru compte le nombre de mots total des deux noms, puis compte le nombre de mots égaux, puis fait la division des deux. Un résultat égalisant ou dépassant le seuil sera considéré comme un doublon. Exemple: "a b c d" et "c d e" ont un pourcentage de 57 (4 mots égaux, 7 au total). + +.. only:: edition_me + + **Type de scan:** Cette option détermine quels aspects du fichier doit être comparé. La nature de la comparaison varie grandement, dépendant de l'option choisie ici. + + * **Nom de fichier:** Le nom de fichier des chansons est comparé, mot-à-mot. + * **Nom de fichier (Champs):** Les noms de fichiers sont séparés en plusieurs champs séparés par le caractère "-". Le pourcentage de comparaison final est le plus petit parmi les champs. Ce type de scan est utile pour comparer les noms de fichier au format "Artiste - Titre" pour lequel le nom de l'artist contient beaucoup de mots (et donc augmente faussement le pourcentage de comparaison). + * **Nom de fichier (Champs sans ordre):** Comme **Nom de fichier (Champs)**, excepté que l'ordre des champs n'a pas d'importance. Par exemple, "Artiste - Titre" et "Titre - Artiste" auraient un pourcentage de 100% au lieu de 0%. + * **Tags:** Méthode de loin la plus utile, elle lit les métadonnées des chansons et le compare mot-à-mot. Comme pour **Nom de fichier (Champs)**, le pourcentage final est le plus bas des champs comparés. + * **Contenu:** Compare le contenu des chansons. Seul un contenu exactement pareil sera considéré comme un doublon. + * **Contenu audio:** Comme **Contenu**, excepté que les métadonnée no sont pas comparées, seulement le contenu audio lui même. Encore une fois, le contenu doit être exactement le même. + + **Seuil du filtre:** Pour les scans basés sur le nom de fichier ou les tags, cette option détermine le degré de similtude nécessaire afin de considérer deux noms comme doublons. Avec un seuil de 80, 80% des mots doivent être égaux. Pour déterminer ce pourcentage, dupeGuru compte le nombre de mots total des deux noms, puis compte le nombre de mots égaux, puis fait la division des deux. Un résultat égalisant ou dépassant le seuil sera considéré comme un doublon. Exemple: "a b c d" et "c d e" ont un pourcentage de 57 (4 mots égaux, 7 au total). + + **Tags à scanner:** Pour les scans de type **Tags**, cette option détermine les tags qui seront comparés. + +.. only:: edition_se or edition_me + + **Proportionalité des mots:** Pour les scans basés sur les mots, cette option change la méthode de calcul afin que les mots plus long pèsent plus dans la balance. Avec cette option, les mots ont une valeur égale à leur longeur. Par exemple, "ab cde fghi" et "ab cde fghij" ont un pourcentage de 53% (19 caractères au total, 10 caractères de mots égaux (4 pour "ab" et 6 pour "cde")). + + **Comparer les mots similaires:** Avec cette options, les mots similaires sont comptés comme égaux. Par exemple, "The White Stripes" et "The White Stripe" ont un pourcentage de 100% au lieu de 66%. **Attention:** Cette option a la potentialité de créer beaucoup de faux doublons. Soyez certains de manuellement vérifier vos résultats avant de les effacer. + +.. only:: edition_pe + + **Type de scan:** Détermine le type de scan qui sera fait sur vos images. Le type **Contenu** compare le contenu des images de façon "fuzzy", rendant possible de trouver non seulement les doublons exactes, mais aussi les similaires. Le type **EXIF Timestamp** compare les métadonnées EXIF des images (si existantes) et détermine si le "timestamp" (moment de prise de la photo) est pareille. C'est beaucoup plus rapide que le scan par Contenu. **Attention:** Les photos modifiées gardent souvent le même timestamp, donc faites attention aux faux doublons si vous utilisez cette méthode. + + **Seuil du filtre:** *Scan par Contenu seulement.* Plus il est élevé, plus les images doivent être similaires pour être considérées comme des doublons. Le défaut de 95% permet quelques petites différence, comme par exemple une différence de qualité ou bien une légère modification des couleurs. + + **Comparer les images de tailles différentes:** Le nom dit tout. Sans cette option, les images de tailles différentes ne sont pas comparées. + +**Comparer les fichiers de différents types:** Sans cette option, seulement les fichiers du même type seront comparés. + +**Ignorer doublons avec hardlink vers le même fichier:** Avec cette option, dupeGuru vérifiera si les doublons pointent vers le même `inode `_. Si oui, ils ne seront pas considérés comme doublons. (Seulement pour OS X et Linux) + +**Utiliser les expressions régulières pour les filtres:** Avec cette option, les filtres appliqués aux résultats seront lus comme des `expressions régulières `_. + +**Effacer les dossiers vides après un déplacement:** Avec cette option, les dossiers se retrouvant vides après avoir effacé ou déplacé des fichiers seront effacés aussi. + +**Déplacements de fichiers:** Détermine comment les opérations de copie et de déplacement s'organiseront pour déterminer la destination finale des fichiers: + +* **Directement à la destination:** Les fichiers sont envoyés directement dans le dossier cible, sans essayer de recréer leur ancienne hierarchie. +* **Re-créer chemins relatifs:** Le chemin du fichier relatif au dossier sélectionné dans la :doc:`sélection de dossier ` sera re-créé. Par exemple, si vous ajoutez ``/Users/foobar/MonDossier`` lors de la sélection de dossier et que vous déplacez ``/Users/foobar/MonDossier/SousDossier/MonFichier.ext`` vers la destination ``/Users/foobar/MaDestination``, la destination finale du fichier sera ``/Users/foobar/MaDestination/SousDossier``. +* **Re-créer chemins absolus:** Le chemin du fichier est re-créé dans son entièreté. Par exemple, si vous déplacez ``/Users/foobar/MonDossier/SousDossier/MonFichier.ext`` vers la destination ``/Users/foobar/MaDestination``, la destination finale du fichier sera ``/Users/foobar/MaDestination/Users/foobar/MonDossier/SousDossier``. + +Dans tous les cas, dupeGuru résout les conflits de noms de fichier en ajoutant un numéro en face du nom. + +**Commande personelle:** Cette option vous permet de définir une ligne de commande à appeler avec le fichier sélectionné (ainsi que sa référence) comme argument. Cette commande sera invoquée quand vous cliquerez sur **Invoquer commande personnalisée**. Cette command est utile si, par exemple, vous avez une application de comparaison visuelle de fichiers que vous aimez bien. + +Le format de la ligne de commande est la même que celle que vous écrireriez manuellement, excepté pour les arguments, **%d** et **%r**. L'endroit où vous placez ces deux arguments sera remplacé par le chemin du fichier sélectionné (%d) et le chemin de son fichier référence dans le groupe (%r). + +Si le chemin de votre executable contient un espace, vous devez le placer entre guillemets "". Vous devriez aussi placer vos arguments %d et %r entre guillemets parce qu'il est très possible d'avoir des chemins de fichier contenant des espaces. Voici un exemple de commande personnelle:: + + "C:\Program Files\SuperDiffProg\SuperDiffProg.exe" "%d" "%r" diff --git a/help/fr/_sources/quick_start.rst.txt b/help/fr/_sources/quick_start.rst.txt new file mode 100644 index 00000000..5a439c08 --- /dev/null +++ b/help/fr/_sources/quick_start.rst.txt @@ -0,0 +1,14 @@ +Démarrage rapide +================= + +Voici les étapes à suivre pour faire un simple scan par défaut: + +* Démarrer dupeGuru. +* Ajouter les dossiers à scanner soit avec le drag & drop, soit avec le boutton "+". +* Cliquez sur **Scan**. +* Attendez que le scan soit completé. +* Vérifiez que les doublons (les fichiers légèrement indentés) soient vraiment le doublon de la référence du groupe (le fichier au haut du groupe qui ne peut pas être marqué). +* Si vous voyer un faux doublon, sélectionnez le puis cliquez sur l'action **Retirer sélectionnés des résultats**. +* Quand vous êtes certains de ne pas avoir de faux doublons dans vos résultats, cliquez sur **Tout marquer** dans le menu Marquer et cliquez sur l'action **Envoyer marqués à la corbeille**. + +Ceci est seulement un scan de base. Il est possible de configurer dupeGuru afin d'obtenir exactement le type de résultat recherché. Pour en savoir plus, il lisez le reste du fichier d'aide. diff --git a/help/fr/_sources/reprioritize.rst.txt b/help/fr/_sources/reprioritize.rst.txt new file mode 100644 index 00000000..4febfca4 --- /dev/null +++ b/help/fr/_sources/reprioritize.rst.txt @@ -0,0 +1,25 @@ +Re-Prioritizing duplicates +========================== + +dupeGuru tries to automatically determine which duplicate should go in each group's reference +position, but sometimes it gets it wrong. In many cases, clever dupe sorting with "Delta Values" +and "Dupes Only" options in addition to the "Make Selected into Reference" action does the trick, +but sometimes, a more powerful option is needed. This is where the Re-Prioritization dialog comes +into play. You can summon it through the "Re-Prioritize Results" item in the "Actions" menu. + +This dialog allows you to select criteria according to which a reference dupe will be selected in +each dupe group. The list of available criteria is on the left and the list of criteria you've +selected is on the right. + +A criteria is a category followed by an argument. For example, "Size (Highest)" means that the dupe +with the biggest size will win. "Folder (/foo/bar)" means that dupes in this folder will win. To add +a criterion to the rightmost list, first select a category in the combobox, then select a +subargument in the list below, and then click on the right pointing arrow button. + +The order of the list on the right is important (you can re-order items through drag & drop). When +picking a dupe for reference position, the first criterion is used. If there's a tie, the second +criterion is used and so on and so on. For example, if your arguments are "Size (Highest)" and then +"Filename (Doesn't end with a number)", the reference file that will be picked in a group will be +the biggest file, and if two or more files have the same size, the one that has a filename that +doesn't end with a number will be used. When all criteria result in ties, the order in which dupes +previously were in the group will be used. \ No newline at end of file diff --git a/help/fr/_sources/results.rst.txt b/help/fr/_sources/results.rst.txt new file mode 100644 index 00000000..45690327 --- /dev/null +++ b/help/fr/_sources/results.rst.txt @@ -0,0 +1,145 @@ +Résultats +========== + +Quand dupeGuru a terminé de scanner, la fenêtre de résultat apparaît avec la liste de groupes de doublons trouvés. + +À propos des groupes de doublons +--------------------------------- + +Un groupe de doublons est un groupe de fichier dans lequel tous les fichiers sont le doublon de tous les autres fichiers. Chaque groupe a son **fichier de référence** (le premier fichier du groupe). Ce fichier est celui qui n'est jamais effacé, et il est donc impossible de le marquer. + +Les critères utilisés pour décider de quel fichier d'un groupe devient la référence sont multiples. Il y a d'abord les dossiers référence. Tout fichier provenant d'un dossier de type "Référence" ne peut être autre chose qu'une référence dans un groupe. Si il n'y a pas de fichiers provenant d'un dossier référence, alors le plus gros fichier est placé comme référence. + +Bien entendu, dans certains cas, il est possible que dupeGuru ne choisisse pas le bon fichier. Dans ce cas, sélectionnez un doublon à placer en position de référence, puis cliquez sur l'action **Transformer sélectionnés en références**. + +Vérifier les résultats +------------------------ + +Bien que vous pouvez tout simplement faire **Tout marquer** puis tous envoyer à la corbeille, il est recommandé de vérifier les résultats avant, surtout si votre seuil de filtre est bas. + +Pour vous aider dans cette tâche, vous pouvez utiliser le panneau de détails. Ce panneau montre les détails du fichier sélectionné côte-à-côte avec sa référence. Vous pouvez aussi double-cliquer sur un fichier pour l'ouvrir avec son application associée. + +Si vous avez plus de faux doublons que de vrais (si votre seuil de filtre est très bas), la meilleure façon de procéder, au lieu de retirer les faux doublons des résultat, serait de marquer seulement les vrais doublons. + +Marquer et sélectionner +----------------------- + +Dans le vocabulaire de dupeGuru, il y a une nette différence entre sélectionner et marquer. Les fichiers **sélectionnés** sont ceux qui sont surlignés dans la liste. On peut sélectionner plusieurs fichiers à la fois en tenant Shift, Control ou Command lorsqu'on clique sur un fichier. + +Les fichiers **marqués** sont ceux avec la petite boite cochée. Il est possible de marquer les fichiers sélectionnés en appuyant sur **espace**. + +Ne pas montrer les références +------------------------------- + +Quand ce mode est activé, les groupes de doublons sont (momentanément) brisés et les doublons sont montrés individuellement, sans leurs références. On peut agir sur les fichiers sous ce mode de la même façon que sous le mode normal. + +L'attrait principal de ce mode est le tri. En mode normal, les groupes ne peuvent pas être brisés, et donc les résultats sont triés en fonction de leur référence. Sous ce mode spécial, le tri est fait au niveau des fichiers individuels. Il est alors possible, par exemple, de facilement marquer tous les fichiers de type "exe": + +* Activer le mode **Ne pas montrer les références**. +* Ajouter la colonne "Type" par le menu "Colonnes". +* Cliquez sur la colonne Type pour changer le tri. +* Trouvez le premier fichier avec un type "exe". +* Sélectionnez-le. +* Trouvez le dernier fichier avec un type "exe". +* Tenez Shift et sélectionnez-le. +* Appuyez sur espace pour marquer les fichiers sélectionnés. + +Montrer les valeurs en tant que delta +------------------------------------- + +Sous ce mode, certaines colonnes montreront leur valeurs relativement à la valeur de la référence du +groupe (de couleur orange, pour bien les différencier des autres valeurs). Par exemple, si un +fichier a une taille de 1.2 MB alors que la référence a une taille de 1.4 MB, la valeur affichée +sous ce mode sera -0.2 MB. + +Les valeurs non numériques sont aussi affectées par le mode delta. Par contre, plutôt que montrer la +différence avec la valeur de référence (ce qui est impossible), elles indiquent si elles sont +pareilles en adoptant la couleur orange dans le cas ou la valeur est différent. Il est ainsi +possible de facilement identifier, par exemple, tous le doublons qui ont un nom de fichier différent +de leur référence. + +Les deux modes ensemble +----------------------- + +Quand on active ces deux modes ensemble, il est alors possible de faire de la sélection de ficher +assez avancée parce que le tri de fichier se fait alors en fonction des valeurs delta. Il devient +alors possible de, par exemple, sélectionner tous les fichiers qui ont une différence de plus de 300 +KB par rapport à leur référence, ou d'autres trucs comme ça. + +Même chose pour les valeurs non numériques: quand les deux modes sont activés, les règles de tri +pour les valeurs non-numériques change. On commence par grouper les doublon selon si leur valeur est +orange ou non, pour ensuite procéder aux règles de tri normales. Avec ce système, il est alors +facile de, par exemple, marquer toues les doublons qui ont un nom de fichier différent de leur +référence: il suffit de trier par nom de fichier. + +Filtrer les résultats +--------------------- + +Il est possible de filtrer les résultats pour agir sur un sous-ensemble de ceux-ci, par exemple tous +les fichiers qui contiennent le mot "copie". + +Pour filtrer les résultats, entrer le filtrer dans le champ de la barre d'outils, puis appuyer sur +Entrée. Pour annuler le filtre, appuyez sur le X dans le champ. + +En mode simple (le mode par défaut), ce que vous tapez est ce qui est filtré. Il n'y a qu'un +caractère spécial: **\***. Ainsi, si vous entrez "[*]", le filtre cherchera pour tout nom contenant +les "[" et "]" avec quelquechose au milieu. + +Pour un filtrage avancé, activez **Utiliser les expressions régulières pour les filtres** dans les +:doc:`preferences`. Votre filtre sera alors appliqué comme une `expression régulière`_. + +Les filtres sont dans tous les cas insensibles aux majuscules et minuscules. + +Les expression régulière pour s'appliquer à un fichier n'ont pas besoin de correspondre au nom +entier. Une correspondance partielle suffit. + +Vous remarquerez peut-être que ce ne sont pas tous les fichiers de vos résultats filtrés qui +s'appliquent au filtre. C'est parce que les groupes ne sont pas brisés par les filtres afin de +permettre une meilleure mise en context. Par contre, ces fichier seront en mode "Lecture seule" et +ne pourront être marqués. + +Actions +------- + +Voici la liste des actions qu'il est possible d'appliquer aux résultats. + +* **Vider la liste de fichiers ignorés:** Ré-initialise la liste des paires de doublons que vous avez ignorés dans le passé. +* **Exporter vers HTML:** Exporte les résultats vers un fichier HTML et l'ouvre dans votre browser. +* **Envoyer marqués à la corbeille:** Le nom le dit. +* **Déplacer marqués vers...:** Déplace les fichiers marqués vers une destination de votre choix. La destination finale du fichier dépend de l'option "Déplacements de fichiers" dans les :doc:`preferences`. +* **Copier marqués vers...:** Même chose que le déplacement, sauf que c'est une copie à la place. +* **Retirer marqués des résultats:** Retire les fichiers marqués des résultats. Ils ne seront donc ni effacés, ni déplacés. +* **Retirer sélectionnés des résultats:** Retire les fichiers sélectionnés des résultats. Notez que si il y a des fichiers références parmi la sélection, ceux-ci sont ignorés par l'action. +* **Transformer sélectionnés en références:** Prend les fichiers sélectionnés et les place à la position de référence de leur groupe respectif. Si l'action est impossible (si la référence provient d'un dossier référence), rien n'est fait. +* **Ajouter sélectionnés à la liste de fichiers ignorés:** Retire les fichiers sélctionnés des résultats, puis les place dans une liste afin que les prochains scans ignorent les paires de doublons qui composaient le groupe dans lequel ces fichiers étaient membres. +* **Ouvrir sélectionné avec l'application par défaut:** Ouvre le fichier sélectionné avec son application associée. +* **Ouvrir le dossier contenant le fichier sélectionné:** Le nom dit tout. +* **Invoquer commande personnalisée:** Invoque la commande personnalisé que vous avez définie dans les :doc:`preferences`. +* **Renommer sélectionné:** Renomme le fichier sélectionné après vous avoir demandé d'entrer un nouveau nom. + +**Déplacer des fichiers dans iPhoto/iTunes:** Attention, quand vous déplacez des fichiers des +bibliothèques iPhoto ou iTunes, elles ne sont pas vraiment déplacées, mais copiée. Il n'y a pas +d'action de déplacement possible dans ces bibliothèques. + +Options de suppression +---------------------- + +Ces options, présentées lors de l'action de suppression de doublons, déterminent comment celle-ci +s'exécute. La plupart du temps, ces options n'ont pas a être activées. + +* **Remplacer les fichiers effacés par des liens:** les fichiers supprimés seront replacés par des + liens (`symlink`_ ou `hardlink`_) vers leur fichiers de référence respectifs. Un symlink est un + lien symbolique (qui devient caduque si l'original est supprimé) et un hardlink est un lien direct + au contenu du fichier (même si l'original est supprimé, le lien reste valide). + + Sur OS X et Linux, cette fonction est supportée pleinement, mais sur Windows, c'est un peu + compliqué. Windows XP ne le supporte pas, mais Vista oui. De plus, cette fonction ne peut être + utilisée que si dupeGuru roule avec les privilèges administratifs. Ouaip, Windows c'est la joie. + +* **Supprimer les fichiers directement:** Plutôt que d'envoyer les doublons à la corbeille, + directement les supprimer. Utiliser cette option si vous avez de la difficulté à supprimer des + fichiers (ce qui arrive quelquefois quand on travaille avec des partages réseau). + +.. _expression régulière: http://www.regular-expressions.info +.. _hardlink: http://en.wikipedia.org/wiki/Hard_link +.. _symlink: http://en.wikipedia.org/wiki/Symbolic_link diff --git a/help/fr/_static/_stemmer.js b/help/fr/_static/_stemmer.js new file mode 100644 index 00000000..3b3c0607 --- /dev/null +++ b/help/fr/_static/_stemmer.js @@ -0,0 +1,3667 @@ +// generatedy by JSX compiler 0.9.89 (2014-05-20 06:01:03 +0900; 8e8c6105f36f3dfe440ea026a3c93a3444977102) +var JSX = {}; +(function (JSX) { +/** + * extends the class + */ +function $__jsx_extend(derivations, base) { + var ctor = function () {}; + ctor.prototype = base.prototype; + var proto = new ctor(); + for (var i in derivations) { + derivations[i].prototype = proto; + } +} + +/** + * copies the implementations from source interface to target + */ +function $__jsx_merge_interface(target, source) { + for (var k in source.prototype) + if (source.prototype.hasOwnProperty(k)) + target.prototype[k] = source.prototype[k]; +} + +/** + * defers the initialization of the property + */ +function $__jsx_lazy_init(obj, prop, func) { + function reset(obj, prop, value) { + delete obj[prop]; + obj[prop] = value; + return value; + } + + Object.defineProperty(obj, prop, { + get: function () { + return reset(obj, prop, func()); + }, + set: function (v) { + reset(obj, prop, v); + }, + enumerable: true, + configurable: true + }); +} + +var $__jsx_imul = Math.imul; +if (typeof $__jsx_imul === "undefined") { + $__jsx_imul = function (a, b) { + var ah = (a >>> 16) & 0xffff; + var al = a & 0xffff; + var bh = (b >>> 16) & 0xffff; + var bl = b & 0xffff; + return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0); + }; +} + +/** + * fused int-ops with side-effects + */ +function $__jsx_ipadd(o, p, r) { + return o[p] = (o[p] + r) | 0; +} +function $__jsx_ipsub(o, p, r) { + return o[p] = (o[p] - r) | 0; +} +function $__jsx_ipmul(o, p, r) { + return o[p] = $__jsx_imul(o[p], r); +} +function $__jsx_ipdiv(o, p, r) { + return o[p] = (o[p] / r) | 0; +} +function $__jsx_ipmod(o, p, r) { + return o[p] = (o[p] % r) | 0; +} +function $__jsx_ippostinc(o, p) { + var v = o[p]; + o[p] = (v + 1) | 0; + return v; +} +function $__jsx_ippostdec(o, p) { + var v = o[p]; + o[p] = (v - 1) | 0; + return v; +} + +/** + * non-inlined version of Array#each + */ +function $__jsx_forEach(o, f) { + var l = o.length; + for (var i = 0; i < l; ++i) + f(o[i]); +} + +/* + * global functions, renamed to avoid conflict with local variable names + */ +var $__jsx_parseInt = parseInt; +var $__jsx_parseFloat = parseFloat; +function $__jsx_isNaN(n) { return n !== n; } +var $__jsx_isFinite = isFinite; + +var $__jsx_encodeURIComponent = encodeURIComponent; +var $__jsx_decodeURIComponent = decodeURIComponent; +var $__jsx_encodeURI = encodeURI; +var $__jsx_decodeURI = decodeURI; + +var $__jsx_ObjectToString = Object.prototype.toString; +var $__jsx_ObjectHasOwnProperty = Object.prototype.hasOwnProperty; + +/* + * profiler object, initialized afterwards + */ +function $__jsx_profiler() { +} + +/* + * public interface to JSX code + */ +JSX.require = function (path) { + var m = $__jsx_classMap[path]; + return m !== undefined ? m : null; +}; + +JSX.profilerIsRunning = function () { + return $__jsx_profiler.getResults != null; +}; + +JSX.getProfileResults = function () { + return ($__jsx_profiler.getResults || function () { return {}; })(); +}; + +JSX.postProfileResults = function (url, cb) { + if ($__jsx_profiler.postResults == null) + throw new Error("profiler has not been turned on"); + return $__jsx_profiler.postResults(url, cb); +}; + +JSX.resetProfileResults = function () { + if ($__jsx_profiler.resetResults == null) + throw new Error("profiler has not been turned on"); + return $__jsx_profiler.resetResults(); +}; +JSX.DEBUG = false; +var GeneratorFunction$0 = +(function () { + try { + return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); + } catch (e) { + return function GeneratorFunction () {}; + } +})(); +var __jsx_generator_object$0 = +(function () { + function __jsx_generator_object() { + this.__next = 0; + this.__loop = null; + this.__seed = null; + this.__value = undefined; + this.__status = 0; // SUSPENDED: 0, ACTIVE: 1, DEAD: 2 + } + + __jsx_generator_object.prototype.next = function (seed) { + switch (this.__status) { + case 0: + this.__status = 1; + this.__seed = seed; + + // go next! + this.__loop(this.__next); + + var done = false; + if (this.__next != -1) { + this.__status = 0; + } else { + this.__status = 2; + done = true; + } + return { value: this.__value, done: done }; + case 1: + throw new Error("Generator is already running"); + case 2: + throw new Error("Generator is already finished"); + default: + throw new Error("Unexpected generator internal state"); + } + }; + + return __jsx_generator_object; +}()); +function Among(s, substring_i, result) { + this.s_size = s.length; + this.s = s; + this.substring_i = substring_i; + this.result = result; + this.method = null; + this.instance = null; +}; + +function Among$0(s, substring_i, result, method, instance) { + this.s_size = s.length; + this.s = s; + this.substring_i = substring_i; + this.result = result; + this.method = method; + this.instance = instance; +}; + +$__jsx_extend([Among, Among$0], Object); +function Stemmer() { +}; + +$__jsx_extend([Stemmer], Object); +function BaseStemmer() { + var current$0; + var cursor$0; + var limit$0; + this.cache = ({ }); + current$0 = this.current = ""; + cursor$0 = this.cursor = 0; + limit$0 = this.limit = current$0.length; + this.limit_backward = 0; + this.bra = cursor$0; + this.ket = limit$0; +}; + +$__jsx_extend([BaseStemmer], Stemmer); +BaseStemmer.prototype.setCurrent$S = function (value) { + var current$0; + var cursor$0; + var limit$0; + current$0 = this.current = value; + cursor$0 = this.cursor = 0; + limit$0 = this.limit = current$0.length; + this.limit_backward = 0; + this.bra = cursor$0; + this.ket = limit$0; +}; + + +function BaseStemmer$setCurrent$LBaseStemmer$S($this, value) { + var current$0; + var cursor$0; + var limit$0; + current$0 = $this.current = value; + cursor$0 = $this.cursor = 0; + limit$0 = $this.limit = current$0.length; + $this.limit_backward = 0; + $this.bra = cursor$0; + $this.ket = limit$0; +}; + +BaseStemmer.setCurrent$LBaseStemmer$S = BaseStemmer$setCurrent$LBaseStemmer$S; + +BaseStemmer.prototype.getCurrent$ = function () { + return this.current; +}; + + +function BaseStemmer$getCurrent$LBaseStemmer$($this) { + return $this.current; +}; + +BaseStemmer.getCurrent$LBaseStemmer$ = BaseStemmer$getCurrent$LBaseStemmer$; + +BaseStemmer.prototype.copy_from$LBaseStemmer$ = function (other) { + this.current = other.current; + this.cursor = other.cursor; + this.limit = other.limit; + this.limit_backward = other.limit_backward; + this.bra = other.bra; + this.ket = other.ket; +}; + + +function BaseStemmer$copy_from$LBaseStemmer$LBaseStemmer$($this, other) { + $this.current = other.current; + $this.cursor = other.cursor; + $this.limit = other.limit; + $this.limit_backward = other.limit_backward; + $this.bra = other.bra; + $this.ket = other.ket; +}; + +BaseStemmer.copy_from$LBaseStemmer$LBaseStemmer$ = BaseStemmer$copy_from$LBaseStemmer$LBaseStemmer$; + +BaseStemmer.prototype.in_grouping$AIII = function (s, min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor >= this.limit) { + return false; + } + ch = this.current.charCodeAt(this.cursor); + if (ch > max || ch < min) { + return false; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$in_grouping$LBaseStemmer$AIII($this, s, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor >= $this.limit) { + return false; + } + ch = $this.current.charCodeAt($this.cursor); + if (ch > max || ch < min) { + return false; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.in_grouping$LBaseStemmer$AIII = BaseStemmer$in_grouping$LBaseStemmer$AIII; + +BaseStemmer.prototype.in_grouping_b$AIII = function (s, min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor <= this.limit_backward) { + return false; + } + ch = this.current.charCodeAt(this.cursor - 1); + if (ch > max || ch < min) { + return false; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$in_grouping_b$LBaseStemmer$AIII($this, s, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor <= $this.limit_backward) { + return false; + } + ch = $this.current.charCodeAt($this.cursor - 1); + if (ch > max || ch < min) { + return false; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.in_grouping_b$LBaseStemmer$AIII = BaseStemmer$in_grouping_b$LBaseStemmer$AIII; + +BaseStemmer.prototype.out_grouping$AIII = function (s, min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor >= this.limit) { + return false; + } + ch = this.current.charCodeAt(this.cursor); + if (ch > max || ch < min) { + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; + } + ch -= min; + if ((s[ch >>> 3] & 0X1 << (ch & 0x7)) === 0) { + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; + } + return false; +}; + + +function BaseStemmer$out_grouping$LBaseStemmer$AIII($this, s, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor >= $this.limit) { + return false; + } + ch = $this.current.charCodeAt($this.cursor); + if (ch > max || ch < min) { + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; + } + ch -= min; + if ((s[ch >>> 3] & 0X1 << (ch & 0x7)) === 0) { + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; + } + return false; +}; + +BaseStemmer.out_grouping$LBaseStemmer$AIII = BaseStemmer$out_grouping$LBaseStemmer$AIII; + +BaseStemmer.prototype.out_grouping_b$AIII = function (s, min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor <= this.limit_backward) { + return false; + } + ch = this.current.charCodeAt(this.cursor - 1); + if (ch > max || ch < min) { + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; + } + return false; +}; + + +function BaseStemmer$out_grouping_b$LBaseStemmer$AIII($this, s, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor <= $this.limit_backward) { + return false; + } + ch = $this.current.charCodeAt($this.cursor - 1); + if (ch > max || ch < min) { + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; + } + return false; +}; + +BaseStemmer.out_grouping_b$LBaseStemmer$AIII = BaseStemmer$out_grouping_b$LBaseStemmer$AIII; + +BaseStemmer.prototype.in_range$II = function (min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor >= this.limit) { + return false; + } + ch = this.current.charCodeAt(this.cursor); + if (ch > max || ch < min) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$in_range$LBaseStemmer$II($this, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor >= $this.limit) { + return false; + } + ch = $this.current.charCodeAt($this.cursor); + if (ch > max || ch < min) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.in_range$LBaseStemmer$II = BaseStemmer$in_range$LBaseStemmer$II; + +BaseStemmer.prototype.in_range_b$II = function (min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor <= this.limit_backward) { + return false; + } + ch = this.current.charCodeAt(this.cursor - 1); + if (ch > max || ch < min) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$in_range_b$LBaseStemmer$II($this, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor <= $this.limit_backward) { + return false; + } + ch = $this.current.charCodeAt($this.cursor - 1); + if (ch > max || ch < min) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.in_range_b$LBaseStemmer$II = BaseStemmer$in_range_b$LBaseStemmer$II; + +BaseStemmer.prototype.out_range$II = function (min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor >= this.limit) { + return false; + } + ch = this.current.charCodeAt(this.cursor); + if (! (ch > max || ch < min)) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$out_range$LBaseStemmer$II($this, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor >= $this.limit) { + return false; + } + ch = $this.current.charCodeAt($this.cursor); + if (! (ch > max || ch < min)) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.out_range$LBaseStemmer$II = BaseStemmer$out_range$LBaseStemmer$II; + +BaseStemmer.prototype.out_range_b$II = function (min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor <= this.limit_backward) { + return false; + } + ch = this.current.charCodeAt(this.cursor - 1); + if (! (ch > max || ch < min)) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$out_range_b$LBaseStemmer$II($this, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor <= $this.limit_backward) { + return false; + } + ch = $this.current.charCodeAt($this.cursor - 1); + if (! (ch > max || ch < min)) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.out_range_b$LBaseStemmer$II = BaseStemmer$out_range_b$LBaseStemmer$II; + +BaseStemmer.prototype.eq_s$IS = function (s_size, s) { + var cursor$0; + if (((this.limit - this.cursor) | 0) < s_size) { + return false; + } + if (this.current.slice(cursor$0 = this.cursor, ((cursor$0 + s_size) | 0)) !== s) { + return false; + } + this.cursor = (this.cursor + s_size) | 0; + return true; +}; + + +function BaseStemmer$eq_s$LBaseStemmer$IS($this, s_size, s) { + var cursor$0; + if ((($this.limit - $this.cursor) | 0) < s_size) { + return false; + } + if ($this.current.slice(cursor$0 = $this.cursor, ((cursor$0 + s_size) | 0)) !== s) { + return false; + } + $this.cursor = ($this.cursor + s_size) | 0; + return true; +}; + +BaseStemmer.eq_s$LBaseStemmer$IS = BaseStemmer$eq_s$LBaseStemmer$IS; + +BaseStemmer.prototype.eq_s_b$IS = function (s_size, s) { + var cursor$0; + if (((this.cursor - this.limit_backward) | 0) < s_size) { + return false; + } + if (this.current.slice((((cursor$0 = this.cursor) - s_size) | 0), cursor$0) !== s) { + return false; + } + this.cursor = (this.cursor - s_size) | 0; + return true; +}; + + +function BaseStemmer$eq_s_b$LBaseStemmer$IS($this, s_size, s) { + var cursor$0; + if ((($this.cursor - $this.limit_backward) | 0) < s_size) { + return false; + } + if ($this.current.slice((((cursor$0 = $this.cursor) - s_size) | 0), cursor$0) !== s) { + return false; + } + $this.cursor = ($this.cursor - s_size) | 0; + return true; +}; + +BaseStemmer.eq_s_b$LBaseStemmer$IS = BaseStemmer$eq_s_b$LBaseStemmer$IS; + +BaseStemmer.prototype.eq_v$S = function (s) { + return BaseStemmer$eq_s$LBaseStemmer$IS(this, s.length, s); +}; + + +function BaseStemmer$eq_v$LBaseStemmer$S($this, s) { + return BaseStemmer$eq_s$LBaseStemmer$IS($this, s.length, s); +}; + +BaseStemmer.eq_v$LBaseStemmer$S = BaseStemmer$eq_v$LBaseStemmer$S; + +BaseStemmer.prototype.eq_v_b$S = function (s) { + return BaseStemmer$eq_s_b$LBaseStemmer$IS(this, s.length, s); +}; + + +function BaseStemmer$eq_v_b$LBaseStemmer$S($this, s) { + return BaseStemmer$eq_s_b$LBaseStemmer$IS($this, s.length, s); +}; + +BaseStemmer.eq_v_b$LBaseStemmer$S = BaseStemmer$eq_v_b$LBaseStemmer$S; + +BaseStemmer.prototype.find_among$ALAmong$I = function (v, v_size) { + var i; + var j; + var c; + var l; + var common_i; + var common_j; + var first_key_inspected; + var k; + var diff; + var common; + var w; + var i2; + var res; + i = 0; + j = v_size; + c = this.cursor; + l = this.limit; + common_i = 0; + common_j = 0; + first_key_inspected = false; + while (true) { + k = i + (j - i >>> 1); + diff = 0; + common = (common_i < common_j ? common_i : common_j); + w = v[k]; + for (i2 = common; i2 < w.s_size; i2++) { + if (c + common === l) { + diff = -1; + break; + } + diff = this.current.charCodeAt(c + common) - w.s.charCodeAt(i2); + if (diff !== 0) { + break; + } + common++; + } + if (diff < 0) { + j = k; + common_j = common; + } else { + i = k; + common_i = common; + } + if (j - i <= 1) { + if (i > 0) { + break; + } + if (j === i) { + break; + } + if (first_key_inspected) { + break; + } + first_key_inspected = true; + } + } + while (true) { + w = v[i]; + if (common_i >= w.s_size) { + this.cursor = (c + w.s_size | 0); + if (w.method == null) { + return w.result; + } + res = w.method(w.instance); + this.cursor = (c + w.s_size | 0); + if (res) { + return w.result; + } + } + i = w.substring_i; + if (i < 0) { + return 0; + } + } + return -1; +}; + + +function BaseStemmer$find_among$LBaseStemmer$ALAmong$I($this, v, v_size) { + var i; + var j; + var c; + var l; + var common_i; + var common_j; + var first_key_inspected; + var k; + var diff; + var common; + var w; + var i2; + var res; + i = 0; + j = v_size; + c = $this.cursor; + l = $this.limit; + common_i = 0; + common_j = 0; + first_key_inspected = false; + while (true) { + k = i + (j - i >>> 1); + diff = 0; + common = (common_i < common_j ? common_i : common_j); + w = v[k]; + for (i2 = common; i2 < w.s_size; i2++) { + if (c + common === l) { + diff = -1; + break; + } + diff = $this.current.charCodeAt(c + common) - w.s.charCodeAt(i2); + if (diff !== 0) { + break; + } + common++; + } + if (diff < 0) { + j = k; + common_j = common; + } else { + i = k; + common_i = common; + } + if (j - i <= 1) { + if (i > 0) { + break; + } + if (j === i) { + break; + } + if (first_key_inspected) { + break; + } + first_key_inspected = true; + } + } + while (true) { + w = v[i]; + if (common_i >= w.s_size) { + $this.cursor = (c + w.s_size | 0); + if (w.method == null) { + return w.result; + } + res = w.method(w.instance); + $this.cursor = (c + w.s_size | 0); + if (res) { + return w.result; + } + } + i = w.substring_i; + if (i < 0) { + return 0; + } + } + return -1; +}; + +BaseStemmer.find_among$LBaseStemmer$ALAmong$I = BaseStemmer$find_among$LBaseStemmer$ALAmong$I; + +BaseStemmer.prototype.find_among_b$ALAmong$I = function (v, v_size) { + var i; + var j; + var c; + var lb; + var common_i; + var common_j; + var first_key_inspected; + var k; + var diff; + var common; + var w; + var i2; + var res; + i = 0; + j = v_size; + c = this.cursor; + lb = this.limit_backward; + common_i = 0; + common_j = 0; + first_key_inspected = false; + while (true) { + k = i + (j - i >> 1); + diff = 0; + common = (common_i < common_j ? common_i : common_j); + w = v[k]; + for (i2 = w.s_size - 1 - common; i2 >= 0; i2--) { + if (c - common === lb) { + diff = -1; + break; + } + diff = this.current.charCodeAt(c - 1 - common) - w.s.charCodeAt(i2); + if (diff !== 0) { + break; + } + common++; + } + if (diff < 0) { + j = k; + common_j = common; + } else { + i = k; + common_i = common; + } + if (j - i <= 1) { + if (i > 0) { + break; + } + if (j === i) { + break; + } + if (first_key_inspected) { + break; + } + first_key_inspected = true; + } + } + while (true) { + w = v[i]; + if (common_i >= w.s_size) { + this.cursor = (c - w.s_size | 0); + if (w.method == null) { + return w.result; + } + res = w.method(this); + this.cursor = (c - w.s_size | 0); + if (res) { + return w.result; + } + } + i = w.substring_i; + if (i < 0) { + return 0; + } + } + return -1; +}; + + +function BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, v, v_size) { + var i; + var j; + var c; + var lb; + var common_i; + var common_j; + var first_key_inspected; + var k; + var diff; + var common; + var w; + var i2; + var res; + i = 0; + j = v_size; + c = $this.cursor; + lb = $this.limit_backward; + common_i = 0; + common_j = 0; + first_key_inspected = false; + while (true) { + k = i + (j - i >> 1); + diff = 0; + common = (common_i < common_j ? common_i : common_j); + w = v[k]; + for (i2 = w.s_size - 1 - common; i2 >= 0; i2--) { + if (c - common === lb) { + diff = -1; + break; + } + diff = $this.current.charCodeAt(c - 1 - common) - w.s.charCodeAt(i2); + if (diff !== 0) { + break; + } + common++; + } + if (diff < 0) { + j = k; + common_j = common; + } else { + i = k; + common_i = common; + } + if (j - i <= 1) { + if (i > 0) { + break; + } + if (j === i) { + break; + } + if (first_key_inspected) { + break; + } + first_key_inspected = true; + } + } + while (true) { + w = v[i]; + if (common_i >= w.s_size) { + $this.cursor = (c - w.s_size | 0); + if (w.method == null) { + return w.result; + } + res = w.method($this); + $this.cursor = (c - w.s_size | 0); + if (res) { + return w.result; + } + } + i = w.substring_i; + if (i < 0) { + return 0; + } + } + return -1; +}; + +BaseStemmer.find_among_b$LBaseStemmer$ALAmong$I = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I; + +BaseStemmer.prototype.replace_s$IIS = function (c_bra, c_ket, s) { + var adjustment; + adjustment = ((s.length - (((c_ket - c_bra) | 0))) | 0); + this.current = this.current.slice(0, c_bra) + s + this.current.slice(c_ket); + this.limit = (this.limit + adjustment) | 0; + if (this.cursor >= c_ket) { + this.cursor = (this.cursor + adjustment) | 0; + } else if (this.cursor > c_bra) { + this.cursor = c_bra; + } + return (adjustment | 0); +}; + + +function BaseStemmer$replace_s$LBaseStemmer$IIS($this, c_bra, c_ket, s) { + var adjustment; + adjustment = ((s.length - (((c_ket - c_bra) | 0))) | 0); + $this.current = $this.current.slice(0, c_bra) + s + $this.current.slice(c_ket); + $this.limit = ($this.limit + adjustment) | 0; + if ($this.cursor >= c_ket) { + $this.cursor = ($this.cursor + adjustment) | 0; + } else if ($this.cursor > c_bra) { + $this.cursor = c_bra; + } + return (adjustment | 0); +}; + +BaseStemmer.replace_s$LBaseStemmer$IIS = BaseStemmer$replace_s$LBaseStemmer$IIS; + +BaseStemmer.prototype.slice_check$ = function () { + var bra$0; + var ket$0; + var limit$0; + return ((bra$0 = this.bra) < 0 || bra$0 > (ket$0 = this.ket) || ket$0 > (limit$0 = this.limit) || limit$0 > this.current.length ? false : true); +}; + + +function BaseStemmer$slice_check$LBaseStemmer$($this) { + var bra$0; + var ket$0; + var limit$0; + return ((bra$0 = $this.bra) < 0 || bra$0 > (ket$0 = $this.ket) || ket$0 > (limit$0 = $this.limit) || limit$0 > $this.current.length ? false : true); +}; + +BaseStemmer.slice_check$LBaseStemmer$ = BaseStemmer$slice_check$LBaseStemmer$; + +BaseStemmer.prototype.slice_from$S = function (s) { + var result; + var bra$0; + var ket$0; + var limit$0; + result = false; + if ((bra$0 = this.bra) < 0 || bra$0 > (ket$0 = this.ket) || ket$0 > (limit$0 = this.limit) || limit$0 > this.current.length ? false : true) { + BaseStemmer$replace_s$LBaseStemmer$IIS(this, this.bra, this.ket, s); + result = true; + } + return result; +}; + + +function BaseStemmer$slice_from$LBaseStemmer$S($this, s) { + var result; + var bra$0; + var ket$0; + var limit$0; + result = false; + if ((bra$0 = $this.bra) < 0 || bra$0 > (ket$0 = $this.ket) || ket$0 > (limit$0 = $this.limit) || limit$0 > $this.current.length ? false : true) { + BaseStemmer$replace_s$LBaseStemmer$IIS($this, $this.bra, $this.ket, s); + result = true; + } + return result; +}; + +BaseStemmer.slice_from$LBaseStemmer$S = BaseStemmer$slice_from$LBaseStemmer$S; + +BaseStemmer.prototype.slice_del$ = function () { + return BaseStemmer$slice_from$LBaseStemmer$S(this, ""); +}; + + +function BaseStemmer$slice_del$LBaseStemmer$($this) { + return BaseStemmer$slice_from$LBaseStemmer$S($this, ""); +}; + +BaseStemmer.slice_del$LBaseStemmer$ = BaseStemmer$slice_del$LBaseStemmer$; + +BaseStemmer.prototype.insert$IIS = function (c_bra, c_ket, s) { + var adjustment; + adjustment = BaseStemmer$replace_s$LBaseStemmer$IIS(this, c_bra, c_ket, s); + if (c_bra <= this.bra) { + this.bra = (this.bra + adjustment) | 0; + } + if (c_bra <= this.ket) { + this.ket = (this.ket + adjustment) | 0; + } +}; + + +function BaseStemmer$insert$LBaseStemmer$IIS($this, c_bra, c_ket, s) { + var adjustment; + adjustment = BaseStemmer$replace_s$LBaseStemmer$IIS($this, c_bra, c_ket, s); + if (c_bra <= $this.bra) { + $this.bra = ($this.bra + adjustment) | 0; + } + if (c_bra <= $this.ket) { + $this.ket = ($this.ket + adjustment) | 0; + } +}; + +BaseStemmer.insert$LBaseStemmer$IIS = BaseStemmer$insert$LBaseStemmer$IIS; + +BaseStemmer.prototype.slice_to$S = function (s) { + var result; + var bra$0; + var ket$0; + var limit$0; + result = ''; + if ((bra$0 = this.bra) < 0 || bra$0 > (ket$0 = this.ket) || ket$0 > (limit$0 = this.limit) || limit$0 > this.current.length ? false : true) { + result = this.current.slice(this.bra, this.ket); + } + return result; +}; + + +function BaseStemmer$slice_to$LBaseStemmer$S($this, s) { + var result; + var bra$0; + var ket$0; + var limit$0; + result = ''; + if ((bra$0 = $this.bra) < 0 || bra$0 > (ket$0 = $this.ket) || ket$0 > (limit$0 = $this.limit) || limit$0 > $this.current.length ? false : true) { + result = $this.current.slice($this.bra, $this.ket); + } + return result; +}; + +BaseStemmer.slice_to$LBaseStemmer$S = BaseStemmer$slice_to$LBaseStemmer$S; + +BaseStemmer.prototype.assign_to$S = function (s) { + return this.current.slice(0, this.limit); +}; + + +function BaseStemmer$assign_to$LBaseStemmer$S($this, s) { + return $this.current.slice(0, $this.limit); +}; + +BaseStemmer.assign_to$LBaseStemmer$S = BaseStemmer$assign_to$LBaseStemmer$S; + +BaseStemmer.prototype.stem$ = function () { + return false; +}; + + +BaseStemmer.prototype.stemWord$S = function (word) { + var result; + var current$0; + var cursor$0; + var limit$0; + result = this.cache['.' + word]; + if (result == null) { + current$0 = this.current = word; + cursor$0 = this.cursor = 0; + limit$0 = this.limit = current$0.length; + this.limit_backward = 0; + this.bra = cursor$0; + this.ket = limit$0; + this.stem$(); + result = this.current; + this.cache['.' + word] = result; + } + return result; +}; + +BaseStemmer.prototype.stemWord = BaseStemmer.prototype.stemWord$S; + +BaseStemmer.prototype.stemWords$AS = function (words) { + var results; + var i; + var word; + var result; + var current$0; + var cursor$0; + var limit$0; + results = [ ]; + for (i = 0; i < words.length; i++) { + word = words[i]; + result = this.cache['.' + word]; + if (result == null) { + current$0 = this.current = word; + cursor$0 = this.cursor = 0; + limit$0 = this.limit = current$0.length; + this.limit_backward = 0; + this.bra = cursor$0; + this.ket = limit$0; + this.stem$(); + result = this.current; + this.cache['.' + word] = result; + } + results.push(result); + } + return results; +}; + +BaseStemmer.prototype.stemWords = BaseStemmer.prototype.stemWords$AS; + +function FrenchStemmer() { + BaseStemmer.call(this); + this.I_p2 = 0; + this.I_p1 = 0; + this.I_pV = 0; +}; + +$__jsx_extend([FrenchStemmer], BaseStemmer); +FrenchStemmer.prototype.copy_from$LFrenchStemmer$ = function (other) { + this.I_p2 = other.I_p2; + this.I_p1 = other.I_p1; + this.I_pV = other.I_pV; + BaseStemmer$copy_from$LBaseStemmer$LBaseStemmer$(this, other); +}; + +FrenchStemmer.prototype.copy_from = FrenchStemmer.prototype.copy_from$LFrenchStemmer$; + +FrenchStemmer.prototype.r_prelude$ = function () { + var v_1; + var v_2; + var v_3; + var v_4; + var lab1; + var lab3; + var lab4; + var lab5; + var lab6; + var lab7; + var lab8; + var lab9; + var cursor$0; + var $__jsx_postinc_t; +replab0: + while (true) { + v_1 = this.cursor; + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + golab2: + while (true) { + v_2 = this.cursor; + lab3 = true; + lab3: + while (lab3 === true) { + lab3 = false; + lab4 = true; + lab4: + while (lab4 === true) { + lab4 = false; + v_3 = this.cursor; + lab5 = true; + lab5: + while (lab5 === true) { + lab5 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + break lab5; + } + this.bra = this.cursor; + lab6 = true; + lab6: + while (lab6 === true) { + lab6 = false; + v_4 = this.cursor; + lab7 = true; + lab7: + while (lab7 === true) { + lab7 = false; + if (! BaseStemmer$eq_s$LBaseStemmer$IS(this, 1, "u")) { + break lab7; + } + this.ket = this.cursor; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + break lab7; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "U")) { + return false; + } + break lab6; + } + this.cursor = v_4; + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + if (! BaseStemmer$eq_s$LBaseStemmer$IS(this, 1, "i")) { + break lab8; + } + this.ket = this.cursor; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + break lab8; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "I")) { + return false; + } + break lab6; + } + this.cursor = v_4; + if (! BaseStemmer$eq_s$LBaseStemmer$IS(this, 1, "y")) { + break lab5; + } + this.ket = this.cursor; + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "Y")) { + return false; + } + } + break lab4; + } + this.cursor = v_3; + lab9 = true; + lab9: + while (lab9 === true) { + lab9 = false; + this.bra = this.cursor; + if (! BaseStemmer$eq_s$LBaseStemmer$IS(this, 1, "y")) { + break lab9; + } + this.ket = this.cursor; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + break lab9; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "Y")) { + return false; + } + break lab4; + } + this.cursor = v_3; + if (! BaseStemmer$eq_s$LBaseStemmer$IS(this, 1, "q")) { + break lab3; + } + this.bra = this.cursor; + if (! BaseStemmer$eq_s$LBaseStemmer$IS(this, 1, "u")) { + break lab3; + } + this.ket = this.cursor; + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "U")) { + return false; + } + } + this.cursor = v_2; + break golab2; + } + cursor$0 = this.cursor = v_2; + if (cursor$0 >= this.limit) { + break lab1; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + continue replab0; + } + this.cursor = v_1; + break replab0; + } + return true; +}; + +FrenchStemmer.prototype.r_prelude = FrenchStemmer.prototype.r_prelude$; + +function FrenchStemmer$r_prelude$LFrenchStemmer$($this) { + var v_1; + var v_2; + var v_3; + var v_4; + var lab1; + var lab3; + var lab4; + var lab5; + var lab6; + var lab7; + var lab8; + var lab9; + var cursor$0; + var $__jsx_postinc_t; +replab0: + while (true) { + v_1 = $this.cursor; + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + golab2: + while (true) { + v_2 = $this.cursor; + lab3 = true; + lab3: + while (lab3 === true) { + lab3 = false; + lab4 = true; + lab4: + while (lab4 === true) { + lab4 = false; + v_3 = $this.cursor; + lab5 = true; + lab5: + while (lab5 === true) { + lab5 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + break lab5; + } + $this.bra = $this.cursor; + lab6 = true; + lab6: + while (lab6 === true) { + lab6 = false; + v_4 = $this.cursor; + lab7 = true; + lab7: + while (lab7 === true) { + lab7 = false; + if (! BaseStemmer$eq_s$LBaseStemmer$IS($this, 1, "u")) { + break lab7; + } + $this.ket = $this.cursor; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + break lab7; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "U")) { + return false; + } + break lab6; + } + $this.cursor = v_4; + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + if (! BaseStemmer$eq_s$LBaseStemmer$IS($this, 1, "i")) { + break lab8; + } + $this.ket = $this.cursor; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + break lab8; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "I")) { + return false; + } + break lab6; + } + $this.cursor = v_4; + if (! BaseStemmer$eq_s$LBaseStemmer$IS($this, 1, "y")) { + break lab5; + } + $this.ket = $this.cursor; + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "Y")) { + return false; + } + } + break lab4; + } + $this.cursor = v_3; + lab9 = true; + lab9: + while (lab9 === true) { + lab9 = false; + $this.bra = $this.cursor; + if (! BaseStemmer$eq_s$LBaseStemmer$IS($this, 1, "y")) { + break lab9; + } + $this.ket = $this.cursor; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + break lab9; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "Y")) { + return false; + } + break lab4; + } + $this.cursor = v_3; + if (! BaseStemmer$eq_s$LBaseStemmer$IS($this, 1, "q")) { + break lab3; + } + $this.bra = $this.cursor; + if (! BaseStemmer$eq_s$LBaseStemmer$IS($this, 1, "u")) { + break lab3; + } + $this.ket = $this.cursor; + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "U")) { + return false; + } + } + $this.cursor = v_2; + break golab2; + } + cursor$0 = $this.cursor = v_2; + if (cursor$0 >= $this.limit) { + break lab1; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + continue replab0; + } + $this.cursor = v_1; + break replab0; + } + return true; +}; + +FrenchStemmer.r_prelude$LFrenchStemmer$ = FrenchStemmer$r_prelude$LFrenchStemmer$; + +FrenchStemmer.prototype.r_mark_regions$ = function () { + var v_1; + var v_2; + var v_4; + var lab0; + var lab1; + var lab2; + var lab3; + var lab5; + var lab6; + var lab8; + var lab10; + var lab12; + var lab14; + var cursor$0; + var limit$0; + var cursor$1; + var $__jsx_postinc_t; + this.I_pV = limit$0 = this.limit; + this.I_p1 = limit$0; + this.I_p2 = limit$0; + v_1 = this.cursor; + lab0 = true; +lab0: + while (lab0 === true) { + lab0 = false; + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + v_2 = this.cursor; + lab2 = true; + lab2: + while (lab2 === true) { + lab2 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + break lab2; + } + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + break lab2; + } + if (this.cursor >= this.limit) { + break lab2; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + break lab1; + } + this.cursor = v_2; + lab3 = true; + lab3: + while (lab3 === true) { + lab3 = false; + if (BaseStemmer$find_among$LBaseStemmer$ALAmong$I(this, FrenchStemmer.a_0, 3) === 0) { + break lab3; + } + break lab1; + } + cursor$0 = this.cursor = v_2; + if (cursor$0 >= this.limit) { + break lab0; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + golab4: + while (true) { + lab5 = true; + lab5: + while (lab5 === true) { + lab5 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + break lab5; + } + break golab4; + } + if (this.cursor >= this.limit) { + break lab0; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + } + this.I_pV = this.cursor; + } + cursor$1 = this.cursor = v_1; + v_4 = cursor$1; + lab6 = true; +lab6: + while (lab6 === true) { + lab6 = false; + golab7: + while (true) { + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + break lab8; + } + break golab7; + } + if (this.cursor >= this.limit) { + break lab6; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + golab9: + while (true) { + lab10 = true; + lab10: + while (lab10 === true) { + lab10 = false; + if (! BaseStemmer$out_grouping$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + break lab10; + } + break golab9; + } + if (this.cursor >= this.limit) { + break lab6; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + this.I_p1 = this.cursor; + golab11: + while (true) { + lab12 = true; + lab12: + while (lab12 === true) { + lab12 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + break lab12; + } + break golab11; + } + if (this.cursor >= this.limit) { + break lab6; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + golab13: + while (true) { + lab14 = true; + lab14: + while (lab14 === true) { + lab14 = false; + if (! BaseStemmer$out_grouping$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + break lab14; + } + break golab13; + } + if (this.cursor >= this.limit) { + break lab6; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + this.I_p2 = this.cursor; + } + this.cursor = v_4; + return true; +}; + +FrenchStemmer.prototype.r_mark_regions = FrenchStemmer.prototype.r_mark_regions$; + +function FrenchStemmer$r_mark_regions$LFrenchStemmer$($this) { + var v_1; + var v_2; + var v_4; + var lab0; + var lab1; + var lab2; + var lab3; + var lab5; + var lab6; + var lab8; + var lab10; + var lab12; + var lab14; + var cursor$0; + var limit$0; + var cursor$1; + var $__jsx_postinc_t; + $this.I_pV = limit$0 = $this.limit; + $this.I_p1 = limit$0; + $this.I_p2 = limit$0; + v_1 = $this.cursor; + lab0 = true; +lab0: + while (lab0 === true) { + lab0 = false; + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + v_2 = $this.cursor; + lab2 = true; + lab2: + while (lab2 === true) { + lab2 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + break lab2; + } + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + break lab2; + } + if ($this.cursor >= $this.limit) { + break lab2; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + break lab1; + } + $this.cursor = v_2; + lab3 = true; + lab3: + while (lab3 === true) { + lab3 = false; + if (BaseStemmer$find_among$LBaseStemmer$ALAmong$I($this, FrenchStemmer.a_0, 3) === 0) { + break lab3; + } + break lab1; + } + cursor$0 = $this.cursor = v_2; + if (cursor$0 >= $this.limit) { + break lab0; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + golab4: + while (true) { + lab5 = true; + lab5: + while (lab5 === true) { + lab5 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + break lab5; + } + break golab4; + } + if ($this.cursor >= $this.limit) { + break lab0; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + } + $this.I_pV = $this.cursor; + } + cursor$1 = $this.cursor = v_1; + v_4 = cursor$1; + lab6 = true; +lab6: + while (lab6 === true) { + lab6 = false; + golab7: + while (true) { + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + break lab8; + } + break golab7; + } + if ($this.cursor >= $this.limit) { + break lab6; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + golab9: + while (true) { + lab10 = true; + lab10: + while (lab10 === true) { + lab10 = false; + if (! BaseStemmer$out_grouping$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + break lab10; + } + break golab9; + } + if ($this.cursor >= $this.limit) { + break lab6; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + $this.I_p1 = $this.cursor; + golab11: + while (true) { + lab12 = true; + lab12: + while (lab12 === true) { + lab12 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + break lab12; + } + break golab11; + } + if ($this.cursor >= $this.limit) { + break lab6; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + golab13: + while (true) { + lab14 = true; + lab14: + while (lab14 === true) { + lab14 = false; + if (! BaseStemmer$out_grouping$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + break lab14; + } + break golab13; + } + if ($this.cursor >= $this.limit) { + break lab6; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + $this.I_p2 = $this.cursor; + } + $this.cursor = v_4; + return true; +}; + +FrenchStemmer.r_mark_regions$LFrenchStemmer$ = FrenchStemmer$r_mark_regions$LFrenchStemmer$; + +FrenchStemmer.prototype.r_postlude$ = function () { + var among_var; + var v_1; + var lab1; + var $__jsx_postinc_t; +replab0: + while (true) { + v_1 = this.cursor; + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + this.bra = this.cursor; + among_var = BaseStemmer$find_among$LBaseStemmer$ALAmong$I(this, FrenchStemmer.a_1, 4); + if (among_var === 0) { + break lab1; + } + this.ket = this.cursor; + switch (among_var) { + case 0: + break lab1; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "i")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "u")) { + return false; + } + break; + case 3: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "y")) { + return false; + } + break; + case 4: + if (this.cursor >= this.limit) { + break lab1; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + break; + } + continue replab0; + } + this.cursor = v_1; + break replab0; + } + return true; +}; + +FrenchStemmer.prototype.r_postlude = FrenchStemmer.prototype.r_postlude$; + +function FrenchStemmer$r_postlude$LFrenchStemmer$($this) { + var among_var; + var v_1; + var lab1; + var $__jsx_postinc_t; +replab0: + while (true) { + v_1 = $this.cursor; + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + $this.bra = $this.cursor; + among_var = BaseStemmer$find_among$LBaseStemmer$ALAmong$I($this, FrenchStemmer.a_1, 4); + if (among_var === 0) { + break lab1; + } + $this.ket = $this.cursor; + switch (among_var) { + case 0: + break lab1; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "i")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "u")) { + return false; + } + break; + case 3: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "y")) { + return false; + } + break; + case 4: + if ($this.cursor >= $this.limit) { + break lab1; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + break; + } + continue replab0; + } + $this.cursor = v_1; + break replab0; + } + return true; +}; + +FrenchStemmer.r_postlude$LFrenchStemmer$ = FrenchStemmer$r_postlude$LFrenchStemmer$; + +FrenchStemmer.prototype.r_RV$ = function () { + return (! (this.I_pV <= this.cursor) ? false : true); +}; + +FrenchStemmer.prototype.r_RV = FrenchStemmer.prototype.r_RV$; + +function FrenchStemmer$r_RV$LFrenchStemmer$($this) { + return (! ($this.I_pV <= $this.cursor) ? false : true); +}; + +FrenchStemmer.r_RV$LFrenchStemmer$ = FrenchStemmer$r_RV$LFrenchStemmer$; + +FrenchStemmer.prototype.r_R1$ = function () { + return (! (this.I_p1 <= this.cursor) ? false : true); +}; + +FrenchStemmer.prototype.r_R1 = FrenchStemmer.prototype.r_R1$; + +function FrenchStemmer$r_R1$LFrenchStemmer$($this) { + return (! ($this.I_p1 <= $this.cursor) ? false : true); +}; + +FrenchStemmer.r_R1$LFrenchStemmer$ = FrenchStemmer$r_R1$LFrenchStemmer$; + +FrenchStemmer.prototype.r_R2$ = function () { + return (! (this.I_p2 <= this.cursor) ? false : true); +}; + +FrenchStemmer.prototype.r_R2 = FrenchStemmer.prototype.r_R2$; + +function FrenchStemmer$r_R2$LFrenchStemmer$($this) { + return (! ($this.I_p2 <= $this.cursor) ? false : true); +}; + +FrenchStemmer.r_R2$LFrenchStemmer$ = FrenchStemmer$r_R2$LFrenchStemmer$; + +FrenchStemmer.prototype.r_standard_suffix$ = function () { + var among_var; + var v_1; + var v_2; + var v_3; + var v_4; + var v_5; + var v_6; + var v_7; + var v_8; + var v_9; + var v_10; + var v_11; + var lab0; + var lab1; + var lab2; + var lab3; + var lab4; + var lab5; + var lab6; + var lab7; + var lab8; + var lab9; + var lab10; + var lab11; + var lab12; + var lab13; + var lab14; + var lab15; + var cursor$0; + var cursor$1; + var cursor$2; + var cursor$3; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, FrenchStemmer.a_4, 43); + if (among_var === 0) { + return false; + } + this.bra = this.cursor; + switch (among_var) { + case 0: + return false; + case 1: + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 2: + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + v_1 = ((this.limit - this.cursor) | 0); + lab0 = true; + lab0: + while (lab0 === true) { + lab0 = false; + this.ket = this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 2, "ic")) { + this.cursor = ((this.limit - v_1) | 0); + break lab0; + } + this.bra = this.cursor; + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + v_2 = ((this.limit - this.cursor) | 0); + lab2 = true; + lab2: + while (lab2 === true) { + lab2 = false; + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + break lab2; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break lab1; + } + this.cursor = ((this.limit - v_2) | 0); + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "iqU")) { + return false; + } + } + } + break; + case 3: + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "log")) { + return false; + } + break; + case 4: + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "u")) { + return false; + } + break; + case 5: + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "ent")) { + return false; + } + break; + case 6: + if (! (! (this.I_pV <= this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + v_3 = ((this.limit - this.cursor) | 0); + lab3 = true; + lab3: + while (lab3 === true) { + lab3 = false; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, FrenchStemmer.a_2, 6); + if (among_var === 0) { + this.cursor = ((this.limit - v_3) | 0); + break lab3; + } + this.bra = this.cursor; + switch (among_var) { + case 0: + this.cursor = ((this.limit - v_3) | 0); + break lab3; + case 1: + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + this.cursor = ((this.limit - v_3) | 0); + break lab3; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + this.ket = this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 2, "at")) { + this.cursor = ((this.limit - v_3) | 0); + break lab3; + } + this.bra = cursor$0 = this.cursor; + if (! (! (this.I_p2 <= cursor$0) ? false : true)) { + this.cursor = ((this.limit - v_3) | 0); + break lab3; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 2: + lab4 = true; + lab4: + while (lab4 === true) { + lab4 = false; + v_4 = ((this.limit - this.cursor) | 0); + lab5 = true; + lab5: + while (lab5 === true) { + lab5 = false; + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + break lab5; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break lab4; + } + cursor$1 = this.cursor = ((this.limit - v_4) | 0); + if (! (! (this.I_p1 <= cursor$1) ? false : true)) { + this.cursor = ((this.limit - v_3) | 0); + break lab3; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "eux")) { + return false; + } + } + break; + case 3: + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + this.cursor = ((this.limit - v_3) | 0); + break lab3; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 4: + if (! (! (this.I_pV <= this.cursor) ? false : true)) { + this.cursor = ((this.limit - v_3) | 0); + break lab3; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "i")) { + return false; + } + break; + } + } + break; + case 7: + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + v_5 = ((this.limit - this.cursor) | 0); + lab6 = true; + lab6: + while (lab6 === true) { + lab6 = false; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, FrenchStemmer.a_3, 3); + if (among_var === 0) { + this.cursor = ((this.limit - v_5) | 0); + break lab6; + } + this.bra = this.cursor; + switch (among_var) { + case 0: + this.cursor = ((this.limit - v_5) | 0); + break lab6; + case 1: + lab7 = true; + lab7: + while (lab7 === true) { + lab7 = false; + v_6 = ((this.limit - this.cursor) | 0); + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + break lab8; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break lab7; + } + this.cursor = ((this.limit - v_6) | 0); + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "abl")) { + return false; + } + } + break; + case 2: + lab9 = true; + lab9: + while (lab9 === true) { + lab9 = false; + v_7 = ((this.limit - this.cursor) | 0); + lab10 = true; + lab10: + while (lab10 === true) { + lab10 = false; + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + break lab10; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break lab9; + } + this.cursor = ((this.limit - v_7) | 0); + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "iqU")) { + return false; + } + } + break; + case 3: + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + this.cursor = ((this.limit - v_5) | 0); + break lab6; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + } + } + break; + case 8: + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + v_8 = ((this.limit - this.cursor) | 0); + lab11 = true; + lab11: + while (lab11 === true) { + lab11 = false; + this.ket = this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 2, "at")) { + this.cursor = ((this.limit - v_8) | 0); + break lab11; + } + this.bra = cursor$2 = this.cursor; + if (! (! (this.I_p2 <= cursor$2) ? false : true)) { + this.cursor = ((this.limit - v_8) | 0); + break lab11; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + this.ket = this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 2, "ic")) { + this.cursor = ((this.limit - v_8) | 0); + break lab11; + } + this.bra = this.cursor; + lab12 = true; + lab12: + while (lab12 === true) { + lab12 = false; + v_9 = ((this.limit - this.cursor) | 0); + lab13 = true; + lab13: + while (lab13 === true) { + lab13 = false; + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + break lab13; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break lab12; + } + this.cursor = ((this.limit - v_9) | 0); + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "iqU")) { + return false; + } + } + } + break; + case 9: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "eau")) { + return false; + } + break; + case 10: + if (! (! (this.I_p1 <= this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "al")) { + return false; + } + break; + case 11: + lab14 = true; + lab14: + while (lab14 === true) { + lab14 = false; + v_10 = ((this.limit - this.cursor) | 0); + lab15 = true; + lab15: + while (lab15 === true) { + lab15 = false; + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + break lab15; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break lab14; + } + cursor$3 = this.cursor = ((this.limit - v_10) | 0); + if (! (! (this.I_p1 <= cursor$3) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "eux")) { + return false; + } + } + break; + case 12: + if (! (! (this.I_p1 <= this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$out_grouping_b$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 13: + if (! (! (this.I_pV <= this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "ant")) { + return false; + } + return false; + case 14: + if (! (! (this.I_pV <= this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "ent")) { + return false; + } + return false; + case 15: + v_11 = ((this.limit - this.cursor) | 0); + if (! BaseStemmer$in_grouping_b$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + return false; + } + if (! (! (this.I_pV <= this.cursor) ? false : true)) { + return false; + } + this.cursor = ((this.limit - v_11) | 0); + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + return false; + } + return true; +}; + +FrenchStemmer.prototype.r_standard_suffix = FrenchStemmer.prototype.r_standard_suffix$; + +function FrenchStemmer$r_standard_suffix$LFrenchStemmer$($this) { + var among_var; + var v_1; + var v_2; + var v_3; + var v_4; + var v_5; + var v_6; + var v_7; + var v_8; + var v_9; + var v_10; + var v_11; + var lab0; + var lab1; + var lab2; + var lab3; + var lab4; + var lab5; + var lab6; + var lab7; + var lab8; + var lab9; + var lab10; + var lab11; + var lab12; + var lab13; + var lab14; + var lab15; + var cursor$0; + var cursor$1; + var cursor$2; + var cursor$3; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, FrenchStemmer.a_4, 43); + if (among_var === 0) { + return false; + } + $this.bra = $this.cursor; + switch (among_var) { + case 0: + return false; + case 1: + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 2: + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + v_1 = (($this.limit - $this.cursor) | 0); + lab0 = true; + lab0: + while (lab0 === true) { + lab0 = false; + $this.ket = $this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 2, "ic")) { + $this.cursor = (($this.limit - v_1) | 0); + break lab0; + } + $this.bra = $this.cursor; + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + v_2 = (($this.limit - $this.cursor) | 0); + lab2 = true; + lab2: + while (lab2 === true) { + lab2 = false; + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + break lab2; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break lab1; + } + $this.cursor = (($this.limit - v_2) | 0); + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "iqU")) { + return false; + } + } + } + break; + case 3: + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "log")) { + return false; + } + break; + case 4: + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "u")) { + return false; + } + break; + case 5: + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "ent")) { + return false; + } + break; + case 6: + if (! (! ($this.I_pV <= $this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + v_3 = (($this.limit - $this.cursor) | 0); + lab3 = true; + lab3: + while (lab3 === true) { + lab3 = false; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, FrenchStemmer.a_2, 6); + if (among_var === 0) { + $this.cursor = (($this.limit - v_3) | 0); + break lab3; + } + $this.bra = $this.cursor; + switch (among_var) { + case 0: + $this.cursor = (($this.limit - v_3) | 0); + break lab3; + case 1: + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + $this.cursor = (($this.limit - v_3) | 0); + break lab3; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + $this.ket = $this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 2, "at")) { + $this.cursor = (($this.limit - v_3) | 0); + break lab3; + } + $this.bra = cursor$0 = $this.cursor; + if (! (! ($this.I_p2 <= cursor$0) ? false : true)) { + $this.cursor = (($this.limit - v_3) | 0); + break lab3; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 2: + lab4 = true; + lab4: + while (lab4 === true) { + lab4 = false; + v_4 = (($this.limit - $this.cursor) | 0); + lab5 = true; + lab5: + while (lab5 === true) { + lab5 = false; + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + break lab5; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break lab4; + } + cursor$1 = $this.cursor = (($this.limit - v_4) | 0); + if (! (! ($this.I_p1 <= cursor$1) ? false : true)) { + $this.cursor = (($this.limit - v_3) | 0); + break lab3; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "eux")) { + return false; + } + } + break; + case 3: + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + $this.cursor = (($this.limit - v_3) | 0); + break lab3; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 4: + if (! (! ($this.I_pV <= $this.cursor) ? false : true)) { + $this.cursor = (($this.limit - v_3) | 0); + break lab3; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "i")) { + return false; + } + break; + } + } + break; + case 7: + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + v_5 = (($this.limit - $this.cursor) | 0); + lab6 = true; + lab6: + while (lab6 === true) { + lab6 = false; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, FrenchStemmer.a_3, 3); + if (among_var === 0) { + $this.cursor = (($this.limit - v_5) | 0); + break lab6; + } + $this.bra = $this.cursor; + switch (among_var) { + case 0: + $this.cursor = (($this.limit - v_5) | 0); + break lab6; + case 1: + lab7 = true; + lab7: + while (lab7 === true) { + lab7 = false; + v_6 = (($this.limit - $this.cursor) | 0); + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + break lab8; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break lab7; + } + $this.cursor = (($this.limit - v_6) | 0); + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "abl")) { + return false; + } + } + break; + case 2: + lab9 = true; + lab9: + while (lab9 === true) { + lab9 = false; + v_7 = (($this.limit - $this.cursor) | 0); + lab10 = true; + lab10: + while (lab10 === true) { + lab10 = false; + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + break lab10; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break lab9; + } + $this.cursor = (($this.limit - v_7) | 0); + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "iqU")) { + return false; + } + } + break; + case 3: + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + $this.cursor = (($this.limit - v_5) | 0); + break lab6; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + } + } + break; + case 8: + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + v_8 = (($this.limit - $this.cursor) | 0); + lab11 = true; + lab11: + while (lab11 === true) { + lab11 = false; + $this.ket = $this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 2, "at")) { + $this.cursor = (($this.limit - v_8) | 0); + break lab11; + } + $this.bra = cursor$2 = $this.cursor; + if (! (! ($this.I_p2 <= cursor$2) ? false : true)) { + $this.cursor = (($this.limit - v_8) | 0); + break lab11; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + $this.ket = $this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 2, "ic")) { + $this.cursor = (($this.limit - v_8) | 0); + break lab11; + } + $this.bra = $this.cursor; + lab12 = true; + lab12: + while (lab12 === true) { + lab12 = false; + v_9 = (($this.limit - $this.cursor) | 0); + lab13 = true; + lab13: + while (lab13 === true) { + lab13 = false; + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + break lab13; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break lab12; + } + $this.cursor = (($this.limit - v_9) | 0); + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "iqU")) { + return false; + } + } + } + break; + case 9: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "eau")) { + return false; + } + break; + case 10: + if (! (! ($this.I_p1 <= $this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "al")) { + return false; + } + break; + case 11: + lab14 = true; + lab14: + while (lab14 === true) { + lab14 = false; + v_10 = (($this.limit - $this.cursor) | 0); + lab15 = true; + lab15: + while (lab15 === true) { + lab15 = false; + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + break lab15; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break lab14; + } + cursor$3 = $this.cursor = (($this.limit - v_10) | 0); + if (! (! ($this.I_p1 <= cursor$3) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "eux")) { + return false; + } + } + break; + case 12: + if (! (! ($this.I_p1 <= $this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$out_grouping_b$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 13: + if (! (! ($this.I_pV <= $this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "ant")) { + return false; + } + return false; + case 14: + if (! (! ($this.I_pV <= $this.cursor) ? false : true)) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "ent")) { + return false; + } + return false; + case 15: + v_11 = (($this.limit - $this.cursor) | 0); + if (! BaseStemmer$in_grouping_b$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + return false; + } + if (! (! ($this.I_pV <= $this.cursor) ? false : true)) { + return false; + } + $this.cursor = (($this.limit - v_11) | 0); + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + return false; + } + return true; +}; + +FrenchStemmer.r_standard_suffix$LFrenchStemmer$ = FrenchStemmer$r_standard_suffix$LFrenchStemmer$; + +FrenchStemmer.prototype.r_i_verb_suffix$ = function () { + var among_var; + var v_1; + var v_2; + var cursor$0; + var cursor$1; + var cursor$2; + v_1 = ((this.limit - (cursor$0 = this.cursor)) | 0); + if (cursor$0 < this.I_pV) { + return false; + } + cursor$1 = this.cursor = this.I_pV; + v_2 = this.limit_backward; + this.limit_backward = cursor$1; + cursor$2 = this.cursor = ((this.limit - v_1) | 0); + this.ket = cursor$2; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, FrenchStemmer.a_5, 35); + if (among_var === 0) { + this.limit_backward = v_2; + return false; + } + this.bra = this.cursor; + switch (among_var) { + case 0: + this.limit_backward = v_2; + return false; + case 1: + if (! BaseStemmer$out_grouping_b$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + this.limit_backward = v_2; + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + } + this.limit_backward = v_2; + return true; +}; + +FrenchStemmer.prototype.r_i_verb_suffix = FrenchStemmer.prototype.r_i_verb_suffix$; + +function FrenchStemmer$r_i_verb_suffix$LFrenchStemmer$($this) { + var among_var; + var v_1; + var v_2; + var cursor$0; + var cursor$1; + var cursor$2; + v_1 = (($this.limit - (cursor$0 = $this.cursor)) | 0); + if (cursor$0 < $this.I_pV) { + return false; + } + cursor$1 = $this.cursor = $this.I_pV; + v_2 = $this.limit_backward; + $this.limit_backward = cursor$1; + cursor$2 = $this.cursor = (($this.limit - v_1) | 0); + $this.ket = cursor$2; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, FrenchStemmer.a_5, 35); + if (among_var === 0) { + $this.limit_backward = v_2; + return false; + } + $this.bra = $this.cursor; + switch (among_var) { + case 0: + $this.limit_backward = v_2; + return false; + case 1: + if (! BaseStemmer$out_grouping_b$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + $this.limit_backward = v_2; + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + } + $this.limit_backward = v_2; + return true; +}; + +FrenchStemmer.r_i_verb_suffix$LFrenchStemmer$ = FrenchStemmer$r_i_verb_suffix$LFrenchStemmer$; + +FrenchStemmer.prototype.r_verb_suffix$ = function () { + var among_var; + var v_1; + var v_2; + var v_3; + var lab0; + var cursor$0; + var cursor$1; + var cursor$2; + v_1 = ((this.limit - (cursor$0 = this.cursor)) | 0); + if (cursor$0 < this.I_pV) { + return false; + } + cursor$1 = this.cursor = this.I_pV; + v_2 = this.limit_backward; + this.limit_backward = cursor$1; + cursor$2 = this.cursor = ((this.limit - v_1) | 0); + this.ket = cursor$2; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, FrenchStemmer.a_6, 38); + if (among_var === 0) { + this.limit_backward = v_2; + return false; + } + this.bra = this.cursor; + switch (among_var) { + case 0: + this.limit_backward = v_2; + return false; + case 1: + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + this.limit_backward = v_2; + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 3: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + v_3 = ((this.limit - this.cursor) | 0); + lab0 = true; + lab0: + while (lab0 === true) { + lab0 = false; + this.ket = this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "e")) { + this.cursor = ((this.limit - v_3) | 0); + break lab0; + } + this.bra = this.cursor; + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + } + break; + } + this.limit_backward = v_2; + return true; +}; + +FrenchStemmer.prototype.r_verb_suffix = FrenchStemmer.prototype.r_verb_suffix$; + +function FrenchStemmer$r_verb_suffix$LFrenchStemmer$($this) { + var among_var; + var v_1; + var v_2; + var v_3; + var lab0; + var cursor$0; + var cursor$1; + var cursor$2; + v_1 = (($this.limit - (cursor$0 = $this.cursor)) | 0); + if (cursor$0 < $this.I_pV) { + return false; + } + cursor$1 = $this.cursor = $this.I_pV; + v_2 = $this.limit_backward; + $this.limit_backward = cursor$1; + cursor$2 = $this.cursor = (($this.limit - v_1) | 0); + $this.ket = cursor$2; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, FrenchStemmer.a_6, 38); + if (among_var === 0) { + $this.limit_backward = v_2; + return false; + } + $this.bra = $this.cursor; + switch (among_var) { + case 0: + $this.limit_backward = v_2; + return false; + case 1: + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + $this.limit_backward = v_2; + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 3: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + v_3 = (($this.limit - $this.cursor) | 0); + lab0 = true; + lab0: + while (lab0 === true) { + lab0 = false; + $this.ket = $this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "e")) { + $this.cursor = (($this.limit - v_3) | 0); + break lab0; + } + $this.bra = $this.cursor; + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + } + break; + } + $this.limit_backward = v_2; + return true; +}; + +FrenchStemmer.r_verb_suffix$LFrenchStemmer$ = FrenchStemmer$r_verb_suffix$LFrenchStemmer$; + +FrenchStemmer.prototype.r_residual_suffix$ = function () { + var among_var; + var v_1; + var v_2; + var v_3; + var v_4; + var v_5; + var lab0; + var lab1; + var lab2; + var cursor$0; + var cursor$1; + var cursor$2; + var cursor$3; + v_1 = ((this.limit - this.cursor) | 0); + lab0 = true; +lab0: + while (lab0 === true) { + lab0 = false; + this.ket = this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "s")) { + this.cursor = ((this.limit - v_1) | 0); + break lab0; + } + this.bra = cursor$0 = this.cursor; + v_2 = ((this.limit - cursor$0) | 0); + if (! BaseStemmer$out_grouping_b$LBaseStemmer$AIII(this, FrenchStemmer.g_keep_with_s, 97, 232)) { + this.cursor = ((this.limit - v_1) | 0); + break lab0; + } + this.cursor = ((this.limit - v_2) | 0); + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + } + v_3 = ((this.limit - (cursor$1 = this.cursor)) | 0); + if (cursor$1 < this.I_pV) { + return false; + } + cursor$2 = this.cursor = this.I_pV; + v_4 = this.limit_backward; + this.limit_backward = cursor$2; + cursor$3 = this.cursor = ((this.limit - v_3) | 0); + this.ket = cursor$3; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, FrenchStemmer.a_7, 7); + if (among_var === 0) { + this.limit_backward = v_4; + return false; + } + this.bra = this.cursor; + switch (among_var) { + case 0: + this.limit_backward = v_4; + return false; + case 1: + if (! (! (this.I_p2 <= this.cursor) ? false : true)) { + this.limit_backward = v_4; + return false; + } + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + v_5 = ((this.limit - this.cursor) | 0); + lab2 = true; + lab2: + while (lab2 === true) { + lab2 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "s")) { + break lab2; + } + break lab1; + } + this.cursor = ((this.limit - v_5) | 0); + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "t")) { + this.limit_backward = v_4; + return false; + } + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "i")) { + return false; + } + break; + case 3: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 4: + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 2, "gu")) { + this.limit_backward = v_4; + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + } + this.limit_backward = v_4; + return true; +}; + +FrenchStemmer.prototype.r_residual_suffix = FrenchStemmer.prototype.r_residual_suffix$; + +function FrenchStemmer$r_residual_suffix$LFrenchStemmer$($this) { + var among_var; + var v_1; + var v_2; + var v_3; + var v_4; + var v_5; + var lab0; + var lab1; + var lab2; + var cursor$0; + var cursor$1; + var cursor$2; + var cursor$3; + v_1 = (($this.limit - $this.cursor) | 0); + lab0 = true; +lab0: + while (lab0 === true) { + lab0 = false; + $this.ket = $this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "s")) { + $this.cursor = (($this.limit - v_1) | 0); + break lab0; + } + $this.bra = cursor$0 = $this.cursor; + v_2 = (($this.limit - cursor$0) | 0); + if (! BaseStemmer$out_grouping_b$LBaseStemmer$AIII($this, FrenchStemmer.g_keep_with_s, 97, 232)) { + $this.cursor = (($this.limit - v_1) | 0); + break lab0; + } + $this.cursor = (($this.limit - v_2) | 0); + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + } + v_3 = (($this.limit - (cursor$1 = $this.cursor)) | 0); + if (cursor$1 < $this.I_pV) { + return false; + } + cursor$2 = $this.cursor = $this.I_pV; + v_4 = $this.limit_backward; + $this.limit_backward = cursor$2; + cursor$3 = $this.cursor = (($this.limit - v_3) | 0); + $this.ket = cursor$3; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, FrenchStemmer.a_7, 7); + if (among_var === 0) { + $this.limit_backward = v_4; + return false; + } + $this.bra = $this.cursor; + switch (among_var) { + case 0: + $this.limit_backward = v_4; + return false; + case 1: + if (! (! ($this.I_p2 <= $this.cursor) ? false : true)) { + $this.limit_backward = v_4; + return false; + } + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + v_5 = (($this.limit - $this.cursor) | 0); + lab2 = true; + lab2: + while (lab2 === true) { + lab2 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "s")) { + break lab2; + } + break lab1; + } + $this.cursor = (($this.limit - v_5) | 0); + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "t")) { + $this.limit_backward = v_4; + return false; + } + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "i")) { + return false; + } + break; + case 3: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 4: + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 2, "gu")) { + $this.limit_backward = v_4; + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + } + $this.limit_backward = v_4; + return true; +}; + +FrenchStemmer.r_residual_suffix$LFrenchStemmer$ = FrenchStemmer$r_residual_suffix$LFrenchStemmer$; + +FrenchStemmer.prototype.r_un_double$ = function () { + var v_1; + var cursor$0; + var $__jsx_postinc_t; + v_1 = ((this.limit - this.cursor) | 0); + if (BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, FrenchStemmer.a_8, 5) === 0) { + return false; + } + cursor$0 = this.cursor = ((this.limit - v_1) | 0); + this.ket = cursor$0; + if (cursor$0 <= this.limit_backward) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + this.bra = this.cursor; + return (! BaseStemmer$slice_from$LBaseStemmer$S(this, "") ? false : true); +}; + +FrenchStemmer.prototype.r_un_double = FrenchStemmer.prototype.r_un_double$; + +function FrenchStemmer$r_un_double$LFrenchStemmer$($this) { + var v_1; + var cursor$0; + var $__jsx_postinc_t; + v_1 = (($this.limit - $this.cursor) | 0); + if (BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, FrenchStemmer.a_8, 5) === 0) { + return false; + } + cursor$0 = $this.cursor = (($this.limit - v_1) | 0); + $this.ket = cursor$0; + if (cursor$0 <= $this.limit_backward) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + $this.bra = $this.cursor; + return (! BaseStemmer$slice_from$LBaseStemmer$S($this, "") ? false : true); +}; + +FrenchStemmer.r_un_double$LFrenchStemmer$ = FrenchStemmer$r_un_double$LFrenchStemmer$; + +FrenchStemmer.prototype.r_un_accent$ = function () { + var v_3; + var v_1; + var lab1; + var lab2; + var lab3; + v_1 = 1; +replab0: + while (true) { + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + if (! BaseStemmer$out_grouping_b$LBaseStemmer$AIII(this, FrenchStemmer.g_v, 97, 251)) { + break lab1; + } + v_1--; + continue replab0; + } + break replab0; + } + if (v_1 > 0) { + return false; + } + this.ket = this.cursor; + lab2 = true; +lab2: + while (lab2 === true) { + lab2 = false; + v_3 = ((this.limit - this.cursor) | 0); + lab3 = true; + lab3: + while (lab3 === true) { + lab3 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "\u00E9")) { + break lab3; + } + break lab2; + } + this.cursor = ((this.limit - v_3) | 0); + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "\u00E8")) { + return false; + } + } + this.bra = this.cursor; + return (! BaseStemmer$slice_from$LBaseStemmer$S(this, "e") ? false : true); +}; + +FrenchStemmer.prototype.r_un_accent = FrenchStemmer.prototype.r_un_accent$; + +function FrenchStemmer$r_un_accent$LFrenchStemmer$($this) { + var v_3; + var v_1; + var lab1; + var lab2; + var lab3; + v_1 = 1; +replab0: + while (true) { + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + if (! BaseStemmer$out_grouping_b$LBaseStemmer$AIII($this, FrenchStemmer.g_v, 97, 251)) { + break lab1; + } + v_1--; + continue replab0; + } + break replab0; + } + if (v_1 > 0) { + return false; + } + $this.ket = $this.cursor; + lab2 = true; +lab2: + while (lab2 === true) { + lab2 = false; + v_3 = (($this.limit - $this.cursor) | 0); + lab3 = true; + lab3: + while (lab3 === true) { + lab3 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "\u00E9")) { + break lab3; + } + break lab2; + } + $this.cursor = (($this.limit - v_3) | 0); + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "\u00E8")) { + return false; + } + } + $this.bra = $this.cursor; + return (! BaseStemmer$slice_from$LBaseStemmer$S($this, "e") ? false : true); +}; + +FrenchStemmer.r_un_accent$LFrenchStemmer$ = FrenchStemmer$r_un_accent$LFrenchStemmer$; + +FrenchStemmer.prototype.stem$ = function () { + var v_1; + var v_2; + var v_3; + var v_4; + var v_5; + var v_6; + var v_7; + var v_8; + var v_9; + var v_11; + var lab0; + var lab1; + var lab2; + var lab3; + var lab4; + var lab5; + var lab6; + var lab7; + var lab8; + var lab9; + var lab10; + var lab11; + var lab12; + var lab13; + var cursor$0; + var limit$0; + var cursor$1; + var cursor$2; + var limit$1; + var cursor$3; + var limit$2; + var cursor$4; + var cursor$5; + v_1 = this.cursor; + lab0 = true; +lab0: + while (lab0 === true) { + lab0 = false; + if (! FrenchStemmer$r_prelude$LFrenchStemmer$(this)) { + break lab0; + } + } + cursor$0 = this.cursor = v_1; + v_2 = cursor$0; + lab1 = true; +lab1: + while (lab1 === true) { + lab1 = false; + if (! FrenchStemmer$r_mark_regions$LFrenchStemmer$(this)) { + break lab1; + } + } + cursor$2 = this.cursor = v_2; + this.limit_backward = cursor$2; + cursor$3 = this.cursor = limit$1 = this.limit; + v_3 = ((limit$1 - cursor$3) | 0); + lab2 = true; +lab2: + while (lab2 === true) { + lab2 = false; + lab3 = true; + lab3: + while (lab3 === true) { + lab3 = false; + v_4 = ((this.limit - this.cursor) | 0); + lab4 = true; + lab4: + while (lab4 === true) { + lab4 = false; + v_5 = ((this.limit - this.cursor) | 0); + lab5 = true; + lab5: + while (lab5 === true) { + lab5 = false; + v_6 = ((this.limit - this.cursor) | 0); + lab6 = true; + lab6: + while (lab6 === true) { + lab6 = false; + if (! FrenchStemmer$r_standard_suffix$LFrenchStemmer$(this)) { + break lab6; + } + break lab5; + } + this.cursor = ((this.limit - v_6) | 0); + lab7 = true; + lab7: + while (lab7 === true) { + lab7 = false; + if (! FrenchStemmer$r_i_verb_suffix$LFrenchStemmer$(this)) { + break lab7; + } + break lab5; + } + this.cursor = ((this.limit - v_6) | 0); + if (! FrenchStemmer$r_verb_suffix$LFrenchStemmer$(this)) { + break lab4; + } + } + cursor$1 = this.cursor = (((limit$0 = this.limit) - v_5) | 0); + v_7 = ((limit$0 - cursor$1) | 0); + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + this.ket = this.cursor; + lab9 = true; + lab9: + while (lab9 === true) { + lab9 = false; + v_8 = ((this.limit - this.cursor) | 0); + lab10 = true; + lab10: + while (lab10 === true) { + lab10 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "Y")) { + break lab10; + } + this.bra = this.cursor; + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "i")) { + return false; + } + break lab9; + } + this.cursor = ((this.limit - v_8) | 0); + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "\u00E7")) { + this.cursor = ((this.limit - v_7) | 0); + break lab8; + } + this.bra = this.cursor; + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "c")) { + return false; + } + } + } + break lab3; + } + this.cursor = ((this.limit - v_4) | 0); + if (! FrenchStemmer$r_residual_suffix$LFrenchStemmer$(this)) { + break lab2; + } + } + } + cursor$4 = this.cursor = (((limit$2 = this.limit) - v_3) | 0); + v_9 = ((limit$2 - cursor$4) | 0); + lab11 = true; +lab11: + while (lab11 === true) { + lab11 = false; + if (! FrenchStemmer$r_un_double$LFrenchStemmer$(this)) { + break lab11; + } + } + this.cursor = ((this.limit - v_9) | 0); + lab12 = true; +lab12: + while (lab12 === true) { + lab12 = false; + if (! FrenchStemmer$r_un_accent$LFrenchStemmer$(this)) { + break lab12; + } + } + cursor$5 = this.cursor = this.limit_backward; + v_11 = cursor$5; + lab13 = true; +lab13: + while (lab13 === true) { + lab13 = false; + if (! FrenchStemmer$r_postlude$LFrenchStemmer$(this)) { + break lab13; + } + } + this.cursor = v_11; + return true; +}; + +FrenchStemmer.prototype.stem = FrenchStemmer.prototype.stem$; + +FrenchStemmer.prototype.equals$X = function (o) { + return o instanceof FrenchStemmer; +}; + +FrenchStemmer.prototype.equals = FrenchStemmer.prototype.equals$X; + +function FrenchStemmer$equals$LFrenchStemmer$X($this, o) { + return o instanceof FrenchStemmer; +}; + +FrenchStemmer.equals$LFrenchStemmer$X = FrenchStemmer$equals$LFrenchStemmer$X; + +FrenchStemmer.prototype.hashCode$ = function () { + var classname; + var hash; + var i; + var char; + classname = "FrenchStemmer"; + hash = 0; + for (i = 0; i < classname.length; i++) { + char = classname.charCodeAt(i); + hash = (hash << 5) - hash + char; + hash = hash & hash; + } + return (hash | 0); +}; + +FrenchStemmer.prototype.hashCode = FrenchStemmer.prototype.hashCode$; + +function FrenchStemmer$hashCode$LFrenchStemmer$($this) { + var classname; + var hash; + var i; + var char; + classname = "FrenchStemmer"; + hash = 0; + for (i = 0; i < classname.length; i++) { + char = classname.charCodeAt(i); + hash = (hash << 5) - hash + char; + hash = hash & hash; + } + return (hash | 0); +}; + +FrenchStemmer.hashCode$LFrenchStemmer$ = FrenchStemmer$hashCode$LFrenchStemmer$; + +FrenchStemmer.serialVersionUID = 1; +$__jsx_lazy_init(FrenchStemmer, "methodObject", function () { + return new FrenchStemmer(); +}); +$__jsx_lazy_init(FrenchStemmer, "a_0", function () { + return [ new Among("col", -1, -1), new Among("par", -1, -1), new Among("tap", -1, -1) ]; +}); +$__jsx_lazy_init(FrenchStemmer, "a_1", function () { + return [ new Among("", -1, 4), new Among("I", 0, 1), new Among("U", 0, 2), new Among("Y", 0, 3) ]; +}); +$__jsx_lazy_init(FrenchStemmer, "a_2", function () { + return [ new Among("iqU", -1, 3), new Among("abl", -1, 3), new Among("I\u00E8r", -1, 4), new Among("i\u00E8r", -1, 4), new Among("eus", -1, 2), new Among("iv", -1, 1) ]; +}); +$__jsx_lazy_init(FrenchStemmer, "a_3", function () { + return [ new Among("ic", -1, 2), new Among("abil", -1, 1), new Among("iv", -1, 3) ]; +}); +$__jsx_lazy_init(FrenchStemmer, "a_4", function () { + return [ new Among("iqUe", -1, 1), new Among("atrice", -1, 2), new Among("ance", -1, 1), new Among("ence", -1, 5), new Among("logie", -1, 3), new Among("able", -1, 1), new Among("isme", -1, 1), new Among("euse", -1, 11), new Among("iste", -1, 1), new Among("ive", -1, 8), new Among("if", -1, 8), new Among("usion", -1, 4), new Among("ation", -1, 2), new Among("ution", -1, 4), new Among("ateur", -1, 2), new Among("iqUes", -1, 1), new Among("atrices", -1, 2), new Among("ances", -1, 1), new Among("ences", -1, 5), new Among("logies", -1, 3), new Among("ables", -1, 1), new Among("ismes", -1, 1), new Among("euses", -1, 11), new Among("istes", -1, 1), new Among("ives", -1, 8), new Among("ifs", -1, 8), new Among("usions", -1, 4), new Among("ations", -1, 2), new Among("utions", -1, 4), new Among("ateurs", -1, 2), new Among("ments", -1, 15), new Among("ements", 30, 6), new Among("issements", 31, 12), new Among("it\u00E9s", -1, 7), new Among("ment", -1, 15), new Among("ement", 34, 6), new Among("issement", 35, 12), new Among("amment", 34, 13), new Among("emment", 34, 14), new Among("aux", -1, 10), new Among("eaux", 39, 9), new Among("eux", -1, 1), new Among("it\u00E9", -1, 7) ]; +}); +$__jsx_lazy_init(FrenchStemmer, "a_5", function () { + return [ new Among("ira", -1, 1), new Among("ie", -1, 1), new Among("isse", -1, 1), new Among("issante", -1, 1), new Among("i", -1, 1), new Among("irai", 4, 1), new Among("ir", -1, 1), new Among("iras", -1, 1), new Among("ies", -1, 1), new Among("\u00EEmes", -1, 1), new Among("isses", -1, 1), new Among("issantes", -1, 1), new Among("\u00EEtes", -1, 1), new Among("is", -1, 1), new Among("irais", 13, 1), new Among("issais", 13, 1), new Among("irions", -1, 1), new Among("issions", -1, 1), new Among("irons", -1, 1), new Among("issons", -1, 1), new Among("issants", -1, 1), new Among("it", -1, 1), new Among("irait", 21, 1), new Among("issait", 21, 1), new Among("issant", -1, 1), new Among("iraIent", -1, 1), new Among("issaIent", -1, 1), new Among("irent", -1, 1), new Among("issent", -1, 1), new Among("iront", -1, 1), new Among("\u00EEt", -1, 1), new Among("iriez", -1, 1), new Among("issiez", -1, 1), new Among("irez", -1, 1), new Among("issez", -1, 1) ]; +}); +$__jsx_lazy_init(FrenchStemmer, "a_6", function () { + return [ new Among("a", -1, 3), new Among("era", 0, 2), new Among("asse", -1, 3), new Among("ante", -1, 3), new Among("\u00E9e", -1, 2), new Among("ai", -1, 3), new Among("erai", 5, 2), new Among("er", -1, 2), new Among("as", -1, 3), new Among("eras", 8, 2), new Among("\u00E2mes", -1, 3), new Among("asses", -1, 3), new Among("antes", -1, 3), new Among("\u00E2tes", -1, 3), new Among("\u00E9es", -1, 2), new Among("ais", -1, 3), new Among("erais", 15, 2), new Among("ions", -1, 1), new Among("erions", 17, 2), new Among("assions", 17, 3), new Among("erons", -1, 2), new Among("ants", -1, 3), new Among("\u00E9s", -1, 2), new Among("ait", -1, 3), new Among("erait", 23, 2), new Among("ant", -1, 3), new Among("aIent", -1, 3), new Among("eraIent", 26, 2), new Among("\u00E8rent", -1, 2), new Among("assent", -1, 3), new Among("eront", -1, 2), new Among("\u00E2t", -1, 3), new Among("ez", -1, 2), new Among("iez", 32, 2), new Among("eriez", 33, 2), new Among("assiez", 33, 3), new Among("erez", 32, 2), new Among("\u00E9", -1, 2) ]; +}); +$__jsx_lazy_init(FrenchStemmer, "a_7", function () { + return [ new Among("e", -1, 3), new Among("I\u00E8re", 0, 2), new Among("i\u00E8re", 0, 2), new Among("ion", -1, 1), new Among("Ier", -1, 2), new Among("ier", -1, 2), new Among("\u00EB", -1, 4) ]; +}); +$__jsx_lazy_init(FrenchStemmer, "a_8", function () { + return [ new Among("ell", -1, -1), new Among("eill", -1, -1), new Among("enn", -1, -1), new Among("onn", -1, -1), new Among("ett", -1, -1) ]; +}); +FrenchStemmer.g_v = [ 17, 65, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 130, 103, 8, 5 ]; +FrenchStemmer.g_keep_with_s = [ 1, 65, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128 ]; + +var $__jsx_classMap = { + "src/among.jsx": { + Among: Among, + Among$SII: Among, + Among$SIIF$LBaseStemmer$B$LBaseStemmer$: Among$0 + }, + "src/stemmer.jsx": { + Stemmer: Stemmer, + Stemmer$: Stemmer + }, + "src/base-stemmer.jsx": { + BaseStemmer: BaseStemmer, + BaseStemmer$: BaseStemmer + }, + "src/french-stemmer.jsx": { + FrenchStemmer: FrenchStemmer, + FrenchStemmer$: FrenchStemmer + } +}; + + +})(JSX); + +var Among = JSX.require("src/among.jsx").Among; +var Among$SII = JSX.require("src/among.jsx").Among$SII; +var Stemmer = JSX.require("src/stemmer.jsx").Stemmer; +var BaseStemmer = JSX.require("src/base-stemmer.jsx").BaseStemmer; +var FrenchStemmer = JSX.require("src/french-stemmer.jsx").FrenchStemmer; diff --git a/help/fr/_static/ajax-loader.gif b/help/fr/_static/ajax-loader.gif new file mode 100644 index 00000000..61faf8ca Binary files /dev/null and b/help/fr/_static/ajax-loader.gif differ diff --git a/help/fr/_static/alert_info_32.png b/help/fr/_static/alert_info_32.png new file mode 100644 index 00000000..ea4d1baf Binary files /dev/null and b/help/fr/_static/alert_info_32.png differ diff --git a/help/fr/_static/alert_warning_32.png b/help/fr/_static/alert_warning_32.png new file mode 100644 index 00000000..a687c3dc Binary files /dev/null and b/help/fr/_static/alert_warning_32.png differ diff --git a/help/fr/_static/basic.css b/help/fr/_static/basic.css new file mode 100644 index 00000000..c7adab45 --- /dev/null +++ b/help/fr/_static/basic.css @@ -0,0 +1,665 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 59em; + max-width: 70em; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/help/fr/_static/bg-page.png b/help/fr/_static/bg-page.png new file mode 100644 index 00000000..fe0a6dc8 Binary files /dev/null and b/help/fr/_static/bg-page.png differ diff --git a/help/fr/_static/bullet_orange.png b/help/fr/_static/bullet_orange.png new file mode 100644 index 00000000..1cb8097c Binary files /dev/null and b/help/fr/_static/bullet_orange.png differ diff --git a/help/fr/_static/comment-bright.png b/help/fr/_static/comment-bright.png new file mode 100644 index 00000000..15e27edb Binary files /dev/null and b/help/fr/_static/comment-bright.png differ diff --git a/help/fr/_static/comment-close.png b/help/fr/_static/comment-close.png new file mode 100644 index 00000000..4d91bcf5 Binary files /dev/null and b/help/fr/_static/comment-close.png differ diff --git a/help/fr/_static/comment.png b/help/fr/_static/comment.png new file mode 100644 index 00000000..dfbc0cbd Binary files /dev/null and b/help/fr/_static/comment.png differ diff --git a/help/fr/_static/doctools.js b/help/fr/_static/doctools.js new file mode 100644 index 00000000..0c15c009 --- /dev/null +++ b/help/fr/_static/doctools.js @@ -0,0 +1,311 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var bbox = span.getBBox(); + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + var parentOfText = node.parentNode.parentNode; + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); \ No newline at end of file diff --git a/help/fr/_static/documentation_options.js b/help/fr/_static/documentation_options.js new file mode 100644 index 00000000..856b9705 --- /dev/null +++ b/help/fr/_static/documentation_options.js @@ -0,0 +1,9 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: '', + VERSION: '4.0.3', + LANGUAGE: 'fr', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' +}; \ No newline at end of file diff --git a/help/fr/_static/down-pressed.png b/help/fr/_static/down-pressed.png new file mode 100644 index 00000000..5756c8ca Binary files /dev/null and b/help/fr/_static/down-pressed.png differ diff --git a/help/fr/_static/down.png b/help/fr/_static/down.png new file mode 100644 index 00000000..1b3bdad2 Binary files /dev/null and b/help/fr/_static/down.png differ diff --git a/help/fr/_static/file.png b/help/fr/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/help/fr/_static/file.png differ diff --git a/help/fr/_static/haiku.css b/help/fr/_static/haiku.css new file mode 100644 index 00000000..75af2a5c --- /dev/null +++ b/help/fr/_static/haiku.css @@ -0,0 +1,376 @@ +/* + * haiku.css_t + * ~~~~~~~~~~~ + * + * Sphinx stylesheet -- haiku theme. + * + * Adapted from http://haiku-os.org/docs/Haiku-doc.css. + * Original copyright message: + * + * Copyright 2008-2009, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Francois Revol + * Stephan Assmus + * Braden Ewing + * Humdinger + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +html { + margin: 0px; + padding: 0px; + background: #FFF url(bg-page.png) top left repeat-x; +} + +body { + line-height: 1.5; + margin: auto; + padding: 0px; + font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; + min-width: 59em; + max-width: 70em; + color: #333333; +} + +div.footer { + padding: 8px; + font-size: 11px; + text-align: center; + letter-spacing: 0.5px; +} + +/* link colors and text decoration */ + +a:link { + font-weight: bold; + text-decoration: none; + color: #dc3c01; +} + +a:visited { + font-weight: bold; + text-decoration: none; + color: #892601; +} + +a:hover, a:active { + text-decoration: underline; + color: #ff4500; +} + +/* Some headers act as anchors, don't give them a hover effect */ + +h1 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h2 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h3 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h4 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +a.headerlink { + color: #a7ce38; + padding-left: 5px; +} + +a.headerlink:hover { + color: #a7ce38; +} + +/* basic text elements */ + +div.content { + margin-top: 20px; + margin-left: 40px; + margin-right: 40px; + margin-bottom: 50px; + font-size: 0.9em; +} + +/* heading and navigation */ + +div.header { + position: relative; + left: 0px; + top: 0px; + height: 85px; + /* background: #eeeeee; */ + padding: 0 40px; +} +div.header h1 { + font-size: 1.6em; + font-weight: normal; + letter-spacing: 1px; + color: #0c3762; + border: 0; + margin: 0; + padding-top: 15px; +} +div.header h1 a { + font-weight: normal; + color: #0c3762; +} +div.header h2 { + font-size: 1.3em; + font-weight: normal; + letter-spacing: 1px; + text-transform: uppercase; + color: #aaa; + border: 0; + margin-top: -3px; + padding: 0; +} + +div.header img.rightlogo { + float: right; +} + + +div.title { + font-size: 1.3em; + font-weight: bold; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-bottom: 25px; +} +div.topnav { + /* background: #e0e0e0; */ +} +div.topnav p { + margin-top: 0; + margin-left: 40px; + margin-right: 40px; + margin-bottom: 0px; + text-align: right; + font-size: 0.8em; +} +div.bottomnav { + background: #eeeeee; +} +div.bottomnav p { + margin-right: 40px; + text-align: right; + font-size: 0.8em; +} + +a.uplink { + font-weight: normal; +} + + +/* contents box */ + +table.index { + margin: 0px 0px 30px 30px; + padding: 1px; + border-width: 1px; + border-style: dotted; + border-color: #e0e0e0; +} +table.index tr.heading { + background-color: #e0e0e0; + text-align: center; + font-weight: bold; + font-size: 1.1em; +} +table.index tr.index { + background-color: #eeeeee; +} +table.index td { + padding: 5px 20px; +} + +table.index a:link, table.index a:visited { + font-weight: normal; + text-decoration: none; + color: #dc3c01; +} +table.index a:hover, table.index a:active { + text-decoration: underline; + color: #ff4500; +} + + +/* Haiku User Guide styles and layout */ + +/* Rounded corner boxes */ +/* Common declarations */ +div.admonition { + -webkit-border-radius: 10px; + -khtml-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; + border-style: dotted; + border-width: thin; + border-color: #dcdcdc; + padding: 10px 15px 10px 15px; + margin-bottom: 15px; + margin-top: 15px; +} +div.note { + padding: 10px 15px 10px 80px; + background: #e4ffde url(alert_info_32.png) 15px 15px no-repeat; + min-height: 42px; +} +div.warning { + padding: 10px 15px 10px 80px; + background: #fffbc6 url(alert_warning_32.png) 15px 15px no-repeat; + min-height: 42px; +} +div.seealso { + background: #e4ffde; +} + +/* More layout and styles */ +h1 { + font-size: 1.3em; + font-weight: bold; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-top: 30px; +} + +h2 { + font-size: 1.2em; + font-weight: normal; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-top: 30px; +} + +h3 { + font-size: 1.1em; + font-weight: normal; + color: #0c3762; + margin-top: 30px; +} + +h4 { + font-size: 1.0em; + font-weight: normal; + color: #0c3762; + margin-top: 30px; +} + +p { + text-align: justify; +} + +p.last { + margin-bottom: 0; +} + +ol { + padding-left: 20px; +} + +ul { + padding-left: 5px; + margin-top: 3px; +} + +li { + line-height: 1.3; +} + +div.content ul > li { + -moz-background-clip:border; + -moz-background-inline-policy:continuous; + -moz-background-origin:padding; + background: transparent url(bullet_orange.png) no-repeat scroll left 0.45em; + list-style-image: none; + list-style-type: none; + padding: 0 0 0 1.666em; + margin-bottom: 3px; +} + +td { + vertical-align: top; +} + +code { + background-color: #e2e2e2; + font-size: 1.0em; + font-family: monospace; +} + +pre { + border-color: #0c3762; + border-style: dotted; + border-width: thin; + margin: 0 0 12px 0; + padding: 0.8em; + background-color: #f0f0f0; +} + +hr { + border-top: 1px solid #ccc; + border-bottom: 0; + border-right: 0; + border-left: 0; + margin-bottom: 10px; + margin-top: 20px; +} + +/* printer only pretty stuff */ +@media print { + .noprint { + display: none; + } + /* for acronyms we want their definitions inlined at print time */ + acronym[title]:after { + font-size: small; + content: " (" attr(title) ")"; + font-style: italic; + } + /* and not have mozilla dotted underline */ + acronym { + border: none; + } + div.topnav, div.bottomnav, div.header, table.index { + display: none; + } + div.content { + margin: 0px; + padding: 0px; + } + html { + background: #FFF; + } +} + +.viewcode-back { + font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; + margin: -1px -10px; + padding: 0 12px; +} + +/* math display */ +div.math p { + text-align: center; +} \ No newline at end of file diff --git a/help/fr/_static/jquery-3.2.1.js b/help/fr/_static/jquery-3.2.1.js new file mode 100644 index 00000000..d2d8ca47 --- /dev/null +++ b/help/fr/_static/jquery-3.2.1.js @@ -0,0 +1,10253 @@ +/*! + * jQuery JavaScript Library v3.2.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2017-03-20T18:59Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.2.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Simple selector that can be filtered directly, removing non-Elements + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + // Complex selector, compare the two sets, removing non-Elements + qualifier = jQuery.filter( qualifier, elements ); + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( jQuery.isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ jQuery.camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( jQuery.camelCase ); + } else { + key = jQuery.camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( ">tbody", elem )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i, + val = 0; + + // If we already have the right measurement, avoid augmentation + if ( extra === ( isBorderBox ? "border" : "content" ) ) { + i = 4; + + // Otherwise initialize for horizontal or vertical properties + } else { + i = name === "width" ? 1 : 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with computed style + var valueIsBorderBox, + styles = getStyles( elem ), + val = curCSS( elem, name, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Fall back to offsetWidth/Height when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + if ( val === "auto" ) { + val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + } + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnothtmlwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, isFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + +
+ + +
+

Changelog

+

About the word « crash »: When reading this changelog, you might be alarmed at the number of fixes +for « crashes ». Be aware that when the word « crash » is used here, it refers to « soft crashes » which +don’t cause the application to quit. You simply get an error window that asks you if you want to +send the crash report to Hardcoded Software. Crashes that cause the application to quit are called +« hard crashes » in this changelog.

+
+

4.0.3 (2016-11-24)

+
    +
  • Add new picture cache backend: shelve
  • +
  • Make shelve picture cache backend the active one on MacOS to fix #394 more +elegantly. [cocoa]
  • +
  • Remove Sparkle (auto-updates) due to technical limitations. [cocoa]
  • +
+
+
+

4.0.2 (2016-10-09)

+
    +
  • Fix systematic crash in Picture Mode under MacOS Sierra. (#394)
  • +
  • No change for Linux. Just keeping version in sync.
  • +
+
+
+

4.0.1 (2016-08-24)

+
    +
  • Add Greek localization, by Gabriel Koutilellis. (#382)
  • +
  • Fix localization base path. [qt] (#378)
  • +
  • Fix broken load results dialog. [qt]
  • +
  • Fix crash on load results. [cocoa] (#380)
  • +
  • Save preferences more predictably. [qt] (#379)
  • +
  • Fix picture mode’s fuzzy block scanner threshold. (#387)
  • +
+
+
+

4.0.0 (2016-07-01)

+
    +
  • Merge Standard, Music and Picture editions in the same application!
  • +
  • Improve documentation. (#294)
  • +
  • Add Polish, Korean, Spanish and Dutch localizations.
  • +
  • qt: Fix wrong use_regexp option propagation to core. (#295)
  • +
  • qt: Fix progress window mistakenly showing up on startup. (#357)
  • +
  • Bump Python requirement to v3.4.
  • +
  • Bump OS X requirement to 10.8
  • +
  • Drop Windows support, maybe temporarily. +Details <https://www.hardcoded.net/archive2015`#2015-11-01>`_
  • +
  • cocoa: Drop iPhoto, Aperture and iTunes support. Was unmaintained and obsolete.
  • +
  • Drop « Audio Contents » scan type. Was confusing and seldom useful.
  • +
  • Change license to GPLv3
  • +
+
+
+

3.9.1 (2014-10-17)

+
    +
  • Fixed AttributeError: 'ComboboxModel' object has no attribute 'reset'. [Linux, Windows] (#254)
  • +
  • Fixed PermissionError on saving results. (#266)
  • +
  • Fixed a build problem introduced by Sphinx 1.2.3.
  • +
  • Updated German localisation, by Frank Weber.
  • +
+
+
+

3.9.0 (2014-04-19)

+
    +
  • This is mostly a dependencies upgrade.
  • +
  • Upgraded to Python 3.3.
  • +
  • Upgraded to Qt 5.
  • +
  • Minimum Windows version is now Windows 7 64bit.
  • +
  • Minimum Ubuntu version is now 14.04.
  • +
  • Minimum OS X version is now 10.7 (Lion).
  • +
  • … But with a couple of little improvements.
  • +
  • Improved documentation.
  • +
  • Overwrite subfolders” state when setting states in folder dialog (#248)
  • +
  • The error report dialog now brings the user to Github issues.
  • +
+
+
+

3.8.0 (2013-12-07)

+
    +
  • Disable symlink/hardlink deletion option when not relevant. (#247)
  • +
  • Make Cmd+A select all folders in the Folder Selection dialog. [Mac] (#228)
  • +
  • Make non-numeric delta comparison case insensitive. (#239)
  • +
  • Fix surrogate-related UnicodeEncodeError on CSV export. (#210)
  • +
  • Fixed crash on Dupe Count sorting with Delta + Dupes Only. (#238)
  • +
  • Improved documentation.
  • +
  • Important internal refactorings.
  • +
  • Dropped Ubuntu 12.04 and 12.10 support.
  • +
  • Removed the fairware dialog (More Info).
  • +
+
+
+

3.7.1 (2013-08-19)

+
    +
  • Fixed folder scan type, which was broken in v3.7.0.
  • +
+
+
+

3.7.0 (2013-08-17)

+
    +
  • Improved delta values to support non-numerical values. (#213)
  • +
  • Improved the Re-Prioritize dialog’s UI. (#224)
  • +
  • Added hardlink/symlink support on Windows Vista+. (#220)
  • +
  • Dropped 32bit support on Mac OS X.
  • +
  • Added Vietnamese localization by Phan Anh.
  • +
+
+
+

3.6.1 (2013-04-28)

+
    +
  • Improved « Make Selection Reference » to make it clearer. (#222)
  • +
  • Improved « Open Selected » to allow opening more than one file at once. (#142)
  • +
  • Fixed a few typos here and there. (#216 #225)
  • +
  • Tweaked the fairware dialog (More Info).
  • +
  • Added Arch Linux packaging
  • +
  • Added a 64-bit build for Windows.
  • +
  • Improved Russian localization by Kyrill Detinov.
  • +
  • Improved Brazilian localization by Victor Figueiredo.
  • +
+
+
+

3.6.0 (2012-08-08)

+
    +
  • Added « Export to CSV ». (#189)
  • +
  • Added « Replace with symlinks » to complement « Replace with hardlinks ». [Mac, Linux] (#194)
  • +
  • dupeGuru now tells how many duplicates were affected after each re-prioritization operation. (#204)
  • +
  • Added Longest/Shortest filename criteria in the re-prioritize dialog. (#198)
  • +
  • Fixed result table cells which mistakenly became writable in v3.5.0. [Mac] (#203)
  • +
  • Fixed « Rename Selected » which was broken since v3.5.0. [Mac] (#202)
  • +
  • Fixed a bug where « Reset to Defaults » in the Columns menu wouldn’t refresh menu items” marked state.
  • +
  • Added Brazilian localization by Victor Figueiredo.
  • +
+
+
+

3.5.0 (2012-06-01)

+
    +
  • Added a Deletion Options panel.
  • +
  • Greatly improved memory usage for big scans.
  • +
  • Added a keybinding for the filter field. (#182) [Mac]
  • +
  • Upgraded minimum requirements for Ubuntu to 12.04.
  • +
+
+
+

3.4.1 (2012-04-14)

+
    +
  • Fixed the « Folders » scan type. [Mac]
  • +
  • Fixed localization issues. [Windows, Linux]
  • +
+
+
+

3.4.0 (2012-03-29)

+
    +
  • Improved results window UI. [Windows, Linux]
  • +
  • Added a dialog to edit the Ignore List.
  • +
  • Added the ability to sort results by « marked » status.
  • +
  • Fixed « Open with default application ». (#190)
  • +
  • Fixed a bug where there would be a false reporting of discarded matches. (#195)
  • +
  • Fixed various localization glitches.
  • +
  • Fixed hard crashes on crash reporting. (#196)
  • +
  • Fixed bug where the details panel would show up at inconvenient places in the screen. [Windows, Linux]
  • +
+
+
+

3.3.3 (2012-02-01)

+
    +
  • Fixed crash on adding some folders. [Mac OS X]
  • +
  • Added Ukrainian localization by Yuri Petrashko.
  • +
+
+
+

3.3.2 (2012-01-16)

+
    +
  • Fixed random hard crashes (yeah, again). [Mac OS X]
  • +
  • Fixed crash on Export to HTML. [Windows, Linux]
  • +
  • Added Armenian localization by Hrant Ohanyan.
  • +
  • Added Russian localization by Igor Pavlov.
  • +
+
+
+

3.3.1 (2011-12-02)

+
    +
  • Fixed a couple of nasty crashes.
  • +
+
+
+

3.3.0 (2011-11-30)

+
    +
  • Added multiple-selection in folder selection dialog for a more efficient folder removal. (#179)
  • +
  • Fixed a crash in the prioritize dialog. (#178)
  • +
  • Fixed a bug where mass marking with a filter would mark more than filtered duplicates. (#181)
  • +
  • Fixed random hard crashes. [Mac OS X] (#183 #184)
  • +
  • Added Czech localization by Aleš Nehyba.
  • +
  • Added Italian localization by Paolo Rossi.
  • +
+
+
+

3.2.1 (2011-10-02)

+
    +
  • Fixed a couple of broken action bindings from v3.2.0.
  • +
+
+
+

3.2.0 (2011-09-27)

+
    +
  • Added duplicate re-prioritization dialog. (#138)
  • +
  • Added font size preference for duplicate table. (#82)
  • +
  • Added Quicklook support. [Mac OS X] (#21)
  • +
  • Improved behavior of Mark Selected. (#139)
  • +
  • Improved filename sorting. (#169)
  • +
  • Added Chinese (Simplified) localization by Eric Dee.
  • +
  • Tweaked the fairware system.
  • +
  • Upgraded minimum requirements to OS X 10.6 and Ubuntu 11.04.
  • +
+
+
+

3.1.2 (2011-08-25)

+
    +
  • Fixed a bug preventing the Folders scan from working. (#172)
  • +
+
+
+

3.1.1 (2011-08-24)

+
    +
  • Added German localization by Gregor Tätzner.
  • +
  • Improved OS X Lion compatibility. [Mac OS X]
  • +
  • Made the file collection phase cancellable. (#168)
  • +
  • Fixed glitch in folder window upon selecting a folder state. [Windows, Linux] (#165)
  • +
  • Fixed a text coloring glitch in the results. (#156)
  • +
  • Fixed glitch in the sorting feature of the Folder column. (#161)
  • +
  • Make sure that saved results have the « .dupeguru » extension. [Linux] (#157)
  • +
+
+
+

3.1.0 (2011-04-16)

+
    +
  • Added the « Folders » scan type. (#89)
  • +
  • Fixed a couple of crashes. (#140 #149)
  • +
+
+
+

3.0.2 (2011-03-16)

+
    +
  • Fixed crash after removing marked dupes. (#140)
  • +
  • Fixed crash on error handling. [Windows] (#144)
  • +
  • Fixed crash on copy/move. [Windows] (#148)
  • +
  • Fixed crash when launching dupeGuru from a very long folder name. [Mac OS X] (#119)
  • +
  • Fixed a refresh bug in directory panel. (#153)
  • +
  • Improved reliability of the « Send to Trash » operation. [Linux]
  • +
  • Tweaked Fairware reminders.
  • +
+
+
+

3.0.1 (2011-01-27)

+
    +
  • Restored the context menu which had been broken in 3.0.0. [Mac OS X] (#133)
  • +
  • Fixed a bug where an « unsaved results » warning would be issued on quit even with empty results. (#134)
  • +
  • Removed focus from the cancel button in the progress dialog to avoid accidental cancellations. [Mac OS X] (#135)
  • +
  • Folders added through drag and drop are added to the recent folders list. (#136)
  • +
  • Added a debugging mode. (#132)
  • +
  • Fixed french localization glitches.
  • +
+
+
+

3.0.0 (2011-01-24)

+
    +
  • Re-designed the UI. (#129)
  • +
  • Internationalized dupeGuru and localized it to french. (#32)
  • +
  • Changed the format of the help file. (#130)
  • +
+
+
+

2.12.3 (2011-01-01)

+
    +
  • Fixed bug causing results to be corrupted after a scan cancellation. (#120)
  • +
  • Fixed crash when fetching Fairware unpaid hours. (#121)
  • +
  • Fixed crash when replacing files with hardlinks. (#122)
  • +
+
+
+

2.12.2 (2010-10-05)

+
    +
  • Fixed delta column colors which were broken since 2.12.0.
  • +
  • Fixed column sorting crash. (#108)
  • +
  • Fixed occasional crash during scan. (#106)
  • +
+
+
+

2.12.1 (2010-09-30)

+
    +
  • Re-licensed dupeGuru to BSD and made it Fairware.
  • +
+
+
+

2.12.0 (2010-09-26)

+
    +
  • Improved UI with a little revamp.
  • +
  • Added the possibility to place hardlinks to references after having deleted duplicates. [Mac OS X, Linux] (#91)
  • +
  • Added an option to ignore duplicates hardlinking to the same file. [Mac OS X, Linux] (#92)
  • +
  • Added multiple selection in the « Add Directory » dialog. [Mac OS X] (#105)
  • +
  • Fixed a bug preventing drag & drop from working in the Directories panel. [Windows, Linux]
  • +
+
+
+

2.11.1 (2010-08-26)

+
    +
  • Fixed HTML exporting which was broken in 2.11.0.
  • +
+
+
+

2.11.0 (2010-08-18)

+
    +
  • Added the ability to save results (and reload them) at arbitrary locations.
  • +
  • Improved the way reference files in dupe groups are chosen. (#15)
  • +
  • Remember size/position of all windows between launches. (#102)
  • +
  • Fixed a bug sometimes preventing dupeGuru from reloading previous results.
  • +
  • Fixed a bug sometimes causing the progress dialog to be stuck there. [Mac OS X] (#103)
  • +
  • Removed the Creation Date column, which wasn’t displaying the correct value anyway. (#101)
  • +
+
+
+

2.10.1 (2010-07-15)

+ +
+
+

2.10.0 (2010-04-13)

+
    +
  • Improved error messages when files can’t be sent to trash, moved or copied.
  • +
  • Added a custom command invocation action. (#12)
  • +
  • Filters are now applied on whole paths. (#4)
  • +
+
+
+

2.9.2 (2010-02-10)

+
    +
  • dupeGuru is now 64-bit on Mac OS X!
  • +
  • Fixed a crash upon quitting when support folder is not present. (#83)
  • +
  • Fixed a crash during sorting. (#85)
  • +
  • Fixed selection glitches, especially while renaming. (#93)
  • +
+
+
+

2.9.1 (2010-01-13)

+
    +
  • Improved memory usage for Contents scans. (#75)
  • +
  • Improved scanning speed when ref directories are involved. (#77)
  • +
  • Show a message dialog at the end of the scan if no duplicates are found. (#81)
  • +
  • Fixed a bug sometimes causing the small files threshold pref to be ignored. [Mac OS X] (#75)
  • +
+
+
+

2.9.0 (2009-11-03)

+
    +
  • Significantly improved speed and memory usage of big contents-based scans.
  • +
  • Added drag & drop support in the Directories panel. (#9)
  • +
  • Fixed a bug causing dupeGuru to be confused if a scanned file was moved during the scan. (#72)
  • +
  • Dropped support for Mac OS X 10.4 (Tiger)
  • +
+
+
+

2.8.2 (2009-10-14)

+
    +
  • Improved directory selection in the Directories panel (Windows). (#56)
  • +
  • Fixed a bug preventing dupeGuru from starting on certain machines (Windows). (#68)
  • +
  • Fixed a crash during very big scans. (#70)
  • +
+
+
+

2.8.1 (2009-10-02)

+
    +
  • Fixed crash with filtering when regular expressions were enabled. (#60)
  • +
  • Fixed crash when setting directories” state. (Mac OS X) (#66)
  • +
  • Fixed crash with Make Reference when certain filters are applied. (Mac OS X) (#55)
  • +
  • Improved error handling during delete/move/copy actions. (#62 #65)
  • +
+
+
+

2.8.0 (2009-09-07)

+
    +
  • Added support for all kinds of bundle (not just applications) (Mac OS X) (#11)
  • +
  • Re-introduced the Export to XHTML feature to Windows. (#14)
  • +
  • Improved Export to XHTML speed. (#14)
  • +
  • Improved Contents scanning speed for large files. (#33)
  • +
  • Improved the grouping algorithm to reduce the number of discarded files in non-exact scans. (#51)
  • +
  • Stopped showing the same file on the 2 sides of the details panel when a ref file is selected. (#50)
  • +
  • Fixed crashes in the Directories panel. (#46)
  • +
+
+
+

2.7.3 (2009-06-20)

+
    +
  • +
    Fixed bugs with selection being jumpy during « Make Reference » actions and Power Marker
    +
    switches. (#3)
    +
    +
  • +
  • Fixed crash happening when a file with non-roman characters couldn’t be analyzed. (#30)
  • +
  • Fixed crash sometimes happening during the file collection phase in scanning. (#38)
  • +
  • Restored double-click and right-click behavior lost in the PyQt move (Windows). (#34 #35)
  • +
+
+
+

2.7.2 (2009-06-10)

+
    +
  • Fixed an occasional crash on Copy/Move operations. (#16)
  • +
  • Added automatic exclusion for sensible folders (like system folders). (#20)
  • +
  • Fixed an occasional crash when application files were part of the results (Mac OS X). (#25)
  • +
+
+
+

2.7.1 (2009-05-29)

+
    +
  • Fixed a bug causing crashes when having application files in the results.
  • +
  • Fixed a bug causing a GUI freeze at the beginning of a scan with a lot of files.
  • +
  • Fixed a bug that sometimes caused a crash when an action was cancelled, and then started again.
  • +
+
+
+

2.7.0 (2009-05-25)

+
    +
  • Converted the Windows GUI to Qt.
  • +
  • Improved the reliability of the scanning process.
  • +
+
+
+

2.6.1 (2009-03-27)

+
    +
  • Fixed an occasional crash caused by permission issues.
  • +
  • +
    Fixed a bug where the « X discarded » notice would show a too large number of discarded
    +
    duplicates.
    +
    +
  • +
+
+
+

2.6.0 (2008-09-10)

+
    +
  • Added a small file threshold preference.
  • +
  • Added a notice in the status bar when matches were discarded during the scan.
  • +
  • Improved duplicate prioritization (smartly chooses which file you will keep).
  • +
  • Improved scan progress feedback.
  • +
  • Improved responsiveness of the user interface for certain actions.
  • +
+
+
+

2.5.4 (2008-08-10)

+
    +
  • Improved the speed of results loading and saving.
  • +
  • Fixed a crash sometimes occurring during duplicate deletion.
  • +
+
+
+

2.5.3 (2008-07-08)

+
    +
  • Improved unicode handling for filenames. dupeGuru will now find a lot more duplicates if your files have non-ascii characters in it.
  • +
  • Fixed « Clear Ignore List » crash in Windows.
  • +
+
+
+

2.5.2 (2008-01-10)

+
    +
  • Improved the handling of low memory situations.
  • +
  • Improved the directory panel. The « Remove » button changes to « Put Back » when an excluded directory is selected.
  • +
  • Improved scan, delete and move speed in situations where there were a lot of duplicates.
  • +
  • Fixed occasional crashes when moving bundles (such as .app files).
  • +
  • Fixed occasional crashes when moving a lot of files at once.
  • +
+
+
+

2.5.1 (2007-11-22)

+
    +
  • Added the « Remove empty folders » option.
  • +
  • Fixed results load/save issues.
  • +
  • Fixed occasional status bar inaccuracies when the results are filtered.
  • +
+
+
+

2.5.0 (2007-09-15)

+
    +
  • Added post scan filtering.
  • +
  • Fixed issues with the rename feature under Windows
  • +
  • Fixed some user interface annoyances under Windows
  • +
+
+
+

2.4.8 (2007-04-14)

+
    +
  • Improved UI responsiveness (using threads) under Mac OS X.
  • +
  • Improved result load/save speed and memory usage.
  • +
+
+
+

2.4.7 (2007-03-10)

+
    +
  • Fixed a « bad file descriptor » error occasionally popping up.
  • +
  • Fixed a bug with non-latin directory names.
  • +
+
+
+

2.4.6 (2007-02-10)

+
    +
  • Added Re-orderable columns. In fact, I re-added the feature which was lost in the C# conversion in 2.4.0 (Windows).
  • +
  • Changed the behavior of the scanning engine when setting the hardness to 100. It will now only match files that have their words in the same order.
  • +
  • Fixed a bug with all the Delete/Move/Copy actions with certain kinds of files.
  • +
+
+
+

2.4.5 (2007-01-11)

+
    +
  • Fixed a bug with the Move action.
  • +
+
+
+

2.4.4 (2007-01-07)

+
    +
  • Fixed a « ghosting » bug. Dupes deleted by dupeGuru would sometimes come back in subsequent scans (Windows).
  • +
  • Fixed bugs sometimes making dupeGuru crash when marking a dupe (Windows).
  • +
  • Fixed some minor visual glitches (Windows).
  • +
+
+
+

2.4.3 (2006-12-08)

+
    +
  • Fixed a mishandling of « .app » files (OS X).
  • +
  • Fixed a bug preventing files from « reference » directories to be displayed in blue in the results (Windows).
  • +
  • Fixed a bug preventing some files to be sent to the recycle bin (Windows).
  • +
  • Fixed a bug in the packaging preventing certain Windows configurations to start dupeGuru at all.
  • +
+
+
+

2.4.2 (2006-11-18)

+
    +
  • Fixed a bug with directory states.
  • +
+
+
+

2.4.1 (2006-11-15)

+
    +
  • Fixed a bug causing the ignore list not to be saved.
  • +
  • Fixed a bug sometimes making delete and move operations stall.
  • +
+
+
+

2.4.0 (2006-11-10)

+
    +
  • Changed the Windows interface. It is now .NET based.
  • +
  • Added an auto-update feature to the windows version.
  • +
  • Changed the way power marking works. It is now a mode instead of a separate window.
  • +
  • Changed the « Size (MB) » column for a « Size (KB) » column. The values are now « ceiled » instead of rounded. Therefore, a size « 0 » is now really 0 bytes, not just a value too small to be rounded up. It is also the case for delta values.
  • +
  • Removed the min word length/count options. These came from Mp3 Filter, and just aren’t used anymore. Word weighting does pretty much the same job.
  • +
+
+
+

2.3.4 (2006-11-07)

+
    +
  • Improved speed and memory usage of the scanning engine, again. Does it mean there was a lot of improvements to be made? Nah…
  • +
+
+
+

2.3.3 (2006-11-02)

+
    +
  • Improved speed and memory usage of the scanning engine, especially when the scan results in a lot of duplicates.
  • +
  • Now I wonder if Sparkle is going to work well…
  • +
+
+
+

2.3.2 (2006-10-16)

+
    +
  • Added an auto-update feature in the Mac OS X version (with Sparkle).
  • +
  • Fixed a bug preventing some duplicate reports to be created correctly under Windows.
  • +
+
+
+

2.3.1 (2006-10-02)

+
    +
  • Fixed a bug preventing some duplicates to be found, especially when scanning lots of files.
  • +
+
+
+

2.3.0 (2006-09-22)

+
    +
  • Added XHTML export feature.
  • +
+
+
+

2.2.10 (2006-08-31)

+
    +
  • Added sticky columns.
  • +
  • Fixed an issue with file caching between scans.
  • +
  • Fixed an issue preventing some duplicates from being deleted/moved/copied.
  • +
+
+
+

2.2.9 (2006-08-27)

+
    +
  • Fixed an issue with ignore list and unicode.
  • +
  • Fixed an issue with file attribute fetching sometimes causing dupeGuru to crash.
  • +
  • Fixed an issue in the directories panel under Windows.
  • +
+
+
+

2.2.8 (2006-08-17)

+
    +
  • Fixed an issue in the duplicate seeking engine preventing some duplicates to be found.
  • +
+
+
+

2.2.7 (2006-08-12)

+
    +
  • Improved unicode support.
  • +
  • Improved the « Reveal in Finder » (« Open Containing Folder » in Windows) feature so it selects the file in the folder it opens.
  • +
+
+
+

2.2.6 (2006-08-07)

+
    +
  • Improved the ignore list system.
  • +
  • dupeGuru is now a Universal application on Mac OS X.
  • +
+
+
+

2.2.5 (2006-07-26)

+
    +
  • Improved application (.app) dupe detection on Mac OS X.
  • +
  • Fixed an issue that occasionally made dupeGuru crash on startup.
  • +
+
+
+

2.2.4 (2006-06-27)

+
    +
  • Fixed an issue with Move and Copy features.
  • +
+
+
+

2.2.3 (2006-06-15)

+
    +
  • Improved duplicate scanning speed.
  • +
  • Added a warning that a file couldn’t be renamed if a file with the same name already exists.
  • +
+
+
+

2.2.2 (2006-06-07)

+
    +
  • Added « Rename Selected » feature.
  • +
  • Fixed some minor issues with « Reload Last Results » feature.
  • +
  • Fixed ignore list issues.
  • +
+
+
+

2.2.1 (2006-05-22)

+
    +
  • Fixed occasional progress bar woes under Windows.
  • +
  • Fixed a bug in the registration system under Windows.
  • +
  • Nothing has been changed in the Mac OS X version, but I want to keep version in sync.
  • +
+
+
+

2.2.0 (2006-05-10)

+
    +
  • Added destination path re-creation options.
  • +
  • Added an ignore list.
  • +
  • Changed the main icon.
  • +
  • Improved dramatically the delta values feature.
  • +
+
+
+

2.1.2 (2006-04-18)

+
    +
  • Added the « Match similar words » option.
  • +
  • Fixed Power marking issues under Mac.
  • +
+
+
+

2.1.1 (2006-04-14)

+
    +
  • Added the « Display delta values » option.
  • +
  • Improved Power marking sorting speed under Mac.
  • +
  • Fixed Power marking sorting issues.
  • +
+
+
+

2.1.0 (2006-04-03)

+
    +
  • Added the Power Marker feature.
  • +
  • Fixed a column sorting bug. The results would sometimes lose their sort order.
  • +
  • Fixed a bug with the Make Reference feature. The results sometimes wasn’t correctly refreshed after the reference switch.
  • +
+
+
+

2.0.1 (2006-03-23)

+
    +
  • Fixed an issue occasionally occurring when trying to reload results from removable media that is no longer present.
  • +
+
+
+

2.0.0 (2006-03-17)

+
    +
  • Complete rewrite.
  • +
  • Now runs on Mac OS X.
  • +
+
+
+

1.0.0 (2004-09-24)

+
    +
  • Initial release.
  • +
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/fr/faq.html b/help/fr/faq.html new file mode 100644 index 00000000..34bc159d --- /dev/null +++ b/help/fr/faq.html @@ -0,0 +1,164 @@ + + + + + + + + Foire aux questions — Documentation dupeGuru 4.0.3 + + + + + + + + + + + + + + + +
+ + +
+

Foire aux questions

+ + +
+

En quoi est-il mieux que les autres applications?

+

dupeGuru est hautement configurable. Vous pouvez changer les options de comparaison afin de trouver +exactement le type de doublons recherché. Plus de détails sur la +page de préférences.

+
+
+

dupeGuru est-il sécuritaire?

+

Oui. dupeGuru a été conçu afin d’être certain que vous conserviez toujours au moins une copie des +doublons que vous trouvez. Il est aussi possible de configurer dupeGuru afin de déterminer certains +dossier à partir desquels aucun fichier ne sera effacé.

+
+
+

Quelles sont les limitation démo de dupeGuru?

+

En mode de démonstration, les actions sont limitées à 10 doublons par session. En mode Fairware, +il n’y a pas de limitation.

+
+
+

Je ne peux pas marquer le doublons que je veux effacer, pourquoi?

+

Tour groupe de doublons contient au moins un fichier dit « référence » et ce fichier ne peut pas être +effacé. Par contre, ce que vous pouvez faire c’est de le remplacer par un autre fichier du groupe. +Pour ce faire, sélectionnez un fichier du groupe et cliquez sur l’action Transformer sélectionnés +en références.

+

Notez que si le fichier référence du groupe vient d’un dossier qui a été défini comme dossier +référence, ce fichier ne peut pas être déplacé de sa position de référence du groupe.

+
+
+

J’ai un dossier duquel je ne veut jamais effacer de fichier.

+

Si vous faites un scan avec un dossier qui ne doit servir que de référence pour effacer des doublons +dans un autre dossier, changez le type de dossier à « Référence » dans la fenêtre de +sélection de dossiers.

+
+
+

Que veut dire “(X hors-groupe)” dans la barre de statut?

+

Lors de certaines comparaisons, il est impossible de correctement grouper les paires de doublons et +certaines paires doivent être retirées des résultats pour être certain de ne pas effacer de faux +doublons. Example: Nous avons 3 fichiers, A, B et C. Nous les comparons en utilisant un petit seuil +de filtre. La comparaison détermine que A est un double de B, A est un double C, mais que B n’est +pas un double de C. dupeGuru a ici un problème. Il ne peut pas créer un groupe avec A, B et C. +Il décide donc de jeter C hors du groupe. C’est de là que vient la notice “(X hors-groupe)”.

+

Cette notice veut dire que si jamais vous effacez tout les doubles contenus dans vos résultats et +que vous faites un nouveau scan, vous pourriez avoir de nouveaux résultats.

+
+
+

Je veux marquer tous les fichiers provenant d’un certain dossier. Quoi faire?

+

Activez l’option Ne pas montrer les références et cliquez sur la colonne Dossier +afin de trier par dossier. Il sera alors facile de sélectionner tous les fichiers de ce dossier +(avec Shift+selection) puis ensuite d’appuyer sur Espace pour marquer les fichiers sélectionnés.

+
+
+

J’essaie d’envoyer mes doublons à la corbeille, mais dupeGuru me dit que je ne peux pas. Pourquoi?

+

La plupart du temps, la raison pour laquelle dupeGuru ne peut pas envoyer des fichiers à la +corbeille est un problème de permissions. Vous devez avoir une permission d’écrire dans les fichiers +que vous voulez effacer. Si vous n’êtes pas familiers avec la ligne de commande, vous pouvez +utiliser des outils comme BatChmod pour modifier vos permissions.

+

Si malgré cela vous ne pouvez toujours pas envoyer vos fichiers à la corbeille, essayez l’option +« Supprimer les fichiers directement » qui vous est offerte lorsque vous procédez à l’effacement des +doublons. Cette option fera en sorte de supprimer directement les fichiers sans les faire passer par +la corbeille. Dans certains cas, ça règle le problème.

+

Dans le pire des cas, contactez le support HS, on trouvera bien.

+
+
+

Où sont les fichiers de configuration de dupeGuru?

+

Si, pour une raison ou une autre, vous voulez effacer ou modifier les fichiers générés par dupeGuru, +voici où ils sont:

+
    +
  • Linux: ~/.local/share/data/Hardcoded Software/dupeGuru
  • +
  • Mac OS X: ~/Library/Application Support/dupeGuru
  • +
  • Windows: \Users\<username>\AppData\Local\Hardcoded Software\dupeGuru
  • +
+

Les fichiers de préférences sont ailleurs:

+
    +
  • Linux: ~/.config/Hardcoded Software/dupeGuru.conf
  • +
  • Mac OS X: Dans le système defaults sous com.hardcoded-software.dupeguru
  • +
  • Windows: Dans le Registre, sous HKEY_CURRENT_USER\Software\Hardcoded Software\dupeGuru
  • +
+

Pour la Music Edition et Picture Edition, remplacer « dupeGuru » par « dupeGuru Music Edition » et +« dupeGuru Picture Edition », respectivement.

+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/fr/folders.html b/help/fr/folders.html new file mode 100644 index 00000000..77017afd --- /dev/null +++ b/help/fr/folders.html @@ -0,0 +1,79 @@ + + + + + + + + Sélection de dossiers — Documentation dupeGuru 4.0.3 + + + + + + + + + + + + + + + +
+ + +
+

Sélection de dossiers

+

La première fenêtre qui apparaît lorsque dupeGuru démarre est la fenêtre de sélection de dossiers à scanner. Elle détermine la liste des dossiers qui seront scannés lorsque vous cliquerez sur Scan.

+

Pour ajouter un dossier, cliquez sur le bouton +. Si vous avez ajouté des dossiers dans le passé, un menu vous permettra de rapidement choisir un de ceux ci. Autrement, il vous sera demandé d’indiquer le dossier à ajouter.

+

Vous pouvez aussi utiliser le drag & drop pour ajouter des dossiers à la liste.

+

Pour retirer un dossier, sélectionnez le et cliquez sur -. Si le dossier sélectionné est un sous-dossier, son type changera pour exclus (voyez plus bas) au lieu d’être retiré.

+
+

Types de dossiers

+

Tout dossier ajouté à la liste est d’un type parmis ces trois:

+
    +
  • Normal: Les doublons trouvés dans ce dossier peuvent être effacés.
  • +
  • Reference: Les doublons trouvés dans ce dossier ne peuvent pas être effacés. Les fichiers provenant de ce dossier ne peuvent qu’être en position « Référence » dans le groupes de doublons.
  • +
  • Excluded: Les fichiers provenant de ce dossier ne sont pas scannés.
  • +
+

Le type par défaut pour un dossier est, bien entendu, Normal. Vous pouvez utiliser le type Référence pour les dossiers desquels vous ne voulez pas effacer de fichiers.

+

Le type d’un dossier s’applique à ses sous-dossiers, excepté si un sous-dossier a un autre type explicitement défini.

+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/fr/genindex.html b/help/fr/genindex.html new file mode 100644 index 00000000..d95cb181 --- /dev/null +++ b/help/fr/genindex.html @@ -0,0 +1,58 @@ + + + + + + + + + Index — Documentation dupeGuru 4.0.3 + + + + + + + + + + + + + +
+ + + +

Index

+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/fr/index.html b/help/fr/index.html new file mode 100644 index 00000000..c31d8d89 --- /dev/null +++ b/help/fr/index.html @@ -0,0 +1,106 @@ + + + + + + + + Aide dupeGuru — Documentation dupeGuru 4.0.3 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/help/fr/objects.inv b/help/fr/objects.inv new file mode 100644 index 00000000..ba8a9ede --- /dev/null +++ b/help/fr/objects.inv @@ -0,0 +1,5 @@ +# Sphinx inventory version 2 +# Project: dupeGuru +# Version: 4.0.3 +# The remainder of this file is compressed using zlib. +xmAN  <FE%Rhg yzm;|z<^ qti/E6˚x U9 E!_Qu>A4&0=כ'\1wZշrm|xef(1fNߧь͖89Ё5[4zgZn]*sQQlWy]FEzHRS~ LdhЪ-;NYߗM* \C.RCRٶWy[G)/<̙ \ No newline at end of file diff --git a/help/fr/preferences.html b/help/fr/preferences.html new file mode 100644 index 00000000..09428e1e --- /dev/null +++ b/help/fr/preferences.html @@ -0,0 +1,81 @@ + + + + + + + + Préférences — Documentation dupeGuru 4.0.3 + + + + + + + + + + + + + + + +
+ + +
+

Préférences

+

Comparer les fichiers de différents types: Sans cette option, seulement les fichiers du même type seront comparés.

+

Ignorer doublons avec hardlink vers le même fichier: Avec cette option, dupeGuru vérifiera si les doublons pointent vers le même inode. Si oui, ils ne seront pas considérés comme doublons. (Seulement pour OS X et Linux)

+

Utiliser les expressions régulières pour les filtres: Avec cette option, les filtres appliqués aux résultats seront lus comme des expressions régulières.

+

Effacer les dossiers vides après un déplacement: Avec cette option, les dossiers se retrouvant vides après avoir effacé ou déplacé des fichiers seront effacés aussi.

+

Déplacements de fichiers: Détermine comment les opérations de copie et de déplacement s’organiseront pour déterminer la destination finale des fichiers:

+
    +
  • Directement à la destination: Les fichiers sont envoyés directement dans le dossier cible, sans essayer de recréer leur ancienne hierarchie.
  • +
  • Re-créer chemins relatifs: Le chemin du fichier relatif au dossier sélectionné dans la sélection de dossier sera re-créé. Par exemple, si vous ajoutez /Users/foobar/MonDossier lors de la sélection de dossier et que vous déplacez /Users/foobar/MonDossier/SousDossier/MonFichier.ext vers la destination /Users/foobar/MaDestination, la destination finale du fichier sera /Users/foobar/MaDestination/SousDossier.
  • +
  • Re-créer chemins absolus: Le chemin du fichier est re-créé dans son entièreté. Par exemple, si vous déplacez /Users/foobar/MonDossier/SousDossier/MonFichier.ext vers la destination /Users/foobar/MaDestination, la destination finale du fichier sera /Users/foobar/MaDestination/Users/foobar/MonDossier/SousDossier.
  • +
+

Dans tous les cas, dupeGuru résout les conflits de noms de fichier en ajoutant un numéro en face du nom.

+

Commande personelle: Cette option vous permet de définir une ligne de commande à appeler avec le fichier sélectionné (ainsi que sa référence) comme argument. Cette commande sera invoquée quand vous cliquerez sur Invoquer commande personnalisée. Cette command est utile si, par exemple, vous avez une application de comparaison visuelle de fichiers que vous aimez bien.

+

Le format de la ligne de commande est la même que celle que vous écrireriez manuellement, excepté pour les arguments, %d et %r. L’endroit où vous placez ces deux arguments sera remplacé par le chemin du fichier sélectionné (%d) et le chemin de son fichier référence dans le groupe (%r).

+

Si le chemin de votre executable contient un espace, vous devez le placer entre guillemets «  ». Vous devriez aussi placer vos arguments %d et %r entre guillemets parce qu’il est très possible d’avoir des chemins de fichier contenant des espaces. Voici un exemple de commande personnelle:

+
"C:\Program Files\SuperDiffProg\SuperDiffProg.exe" "%d" "%r"
+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/fr/quick_start.html b/help/fr/quick_start.html new file mode 100644 index 00000000..7fa6b636 --- /dev/null +++ b/help/fr/quick_start.html @@ -0,0 +1,75 @@ + + + + + + + + Démarrage rapide — Documentation dupeGuru 4.0.3 + + + + + + + + + + + + + + + +
+ + +
+

Démarrage rapide

+

Voici les étapes à suivre pour faire un simple scan par défaut:

+
    +
  • Démarrer dupeGuru.
  • +
  • Ajouter les dossiers à scanner soit avec le drag & drop, soit avec le boutton « + ».
  • +
  • Cliquez sur Scan.
  • +
  • Attendez que le scan soit completé.
  • +
  • Vérifiez que les doublons (les fichiers légèrement indentés) soient vraiment le doublon de la référence du groupe (le fichier au haut du groupe qui ne peut pas être marqué).
  • +
  • Si vous voyer un faux doublon, sélectionnez le puis cliquez sur l’action Retirer sélectionnés des résultats.
  • +
  • Quand vous êtes certains de ne pas avoir de faux doublons dans vos résultats, cliquez sur Tout marquer dans le menu Marquer et cliquez sur l’action Envoyer marqués à la corbeille.
  • +
+

Ceci est seulement un scan de base. Il est possible de configurer dupeGuru afin d’obtenir exactement le type de résultat recherché. Pour en savoir plus, il lisez le reste du fichier d’aide.

+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/fr/reprioritize.html b/help/fr/reprioritize.html new file mode 100644 index 00000000..b5dd3877 --- /dev/null +++ b/help/fr/reprioritize.html @@ -0,0 +1,83 @@ + + + + + + + + Re-Prioritizing duplicates — Documentation dupeGuru 4.0.3 + + + + + + + + + + + + + + + +
+ + +
+

Re-Prioritizing duplicates

+

dupeGuru tries to automatically determine which duplicate should go in each group’s reference +position, but sometimes it gets it wrong. In many cases, clever dupe sorting with « Delta Values » +and « Dupes Only » options in addition to the « Make Selected into Reference » action does the trick, +but sometimes, a more powerful option is needed. This is where the Re-Prioritization dialog comes +into play. You can summon it through the « Re-Prioritize Results » item in the « Actions » menu.

+

This dialog allows you to select criteria according to which a reference dupe will be selected in +each dupe group. The list of available criteria is on the left and the list of criteria you’ve +selected is on the right.

+

A criteria is a category followed by an argument. For example, « Size (Highest) » means that the dupe +with the biggest size will win. « Folder (/foo/bar) » means that dupes in this folder will win. To add +a criterion to the rightmost list, first select a category in the combobox, then select a +subargument in the list below, and then click on the right pointing arrow button.

+

The order of the list on the right is important (you can re-order items through drag & drop). When +picking a dupe for reference position, the first criterion is used. If there’s a tie, the second +criterion is used and so on and so on. For example, if your arguments are « Size (Highest) » and then +« Filename (Doesn’t end with a number) », the reference file that will be picked in a group will be +the biggest file, and if two or more files have the same size, the one that has a filename that +doesn’t end with a number will be used. When all criteria result in ties, the order in which dupes +previously were in the group will be used.

+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/fr/results.html b/help/fr/results.html new file mode 100644 index 00000000..1f5b5b81 --- /dev/null +++ b/help/fr/results.html @@ -0,0 +1,181 @@ + + + + + + + + Résultats — Documentation dupeGuru 4.0.3 + + + + + + + + + + + + + + + +
+ + +
+

Résultats

+

Quand dupeGuru a terminé de scanner, la fenêtre de résultat apparaît avec la liste de groupes de doublons trouvés.

+
+

À propos des groupes de doublons

+

Un groupe de doublons est un groupe de fichier dans lequel tous les fichiers sont le doublon de tous les autres fichiers. Chaque groupe a son fichier de référence (le premier fichier du groupe). Ce fichier est celui qui n’est jamais effacé, et il est donc impossible de le marquer.

+

Les critères utilisés pour décider de quel fichier d’un groupe devient la référence sont multiples. Il y a d’abord les dossiers référence. Tout fichier provenant d’un dossier de type « Référence » ne peut être autre chose qu’une référence dans un groupe. Si il n’y a pas de fichiers provenant d’un dossier référence, alors le plus gros fichier est placé comme référence.

+

Bien entendu, dans certains cas, il est possible que dupeGuru ne choisisse pas le bon fichier. Dans ce cas, sélectionnez un doublon à placer en position de référence, puis cliquez sur l’action Transformer sélectionnés en références.

+
+
+

Vérifier les résultats

+

Bien que vous pouvez tout simplement faire Tout marquer puis tous envoyer à la corbeille, il est recommandé de vérifier les résultats avant, surtout si votre seuil de filtre est bas.

+

Pour vous aider dans cette tâche, vous pouvez utiliser le panneau de détails. Ce panneau montre les détails du fichier sélectionné côte-à-côte avec sa référence. Vous pouvez aussi double-cliquer sur un fichier pour l’ouvrir avec son application associée.

+

Si vous avez plus de faux doublons que de vrais (si votre seuil de filtre est très bas), la meilleure façon de procéder, au lieu de retirer les faux doublons des résultat, serait de marquer seulement les vrais doublons.

+
+
+

Marquer et sélectionner

+

Dans le vocabulaire de dupeGuru, il y a une nette différence entre sélectionner et marquer. Les fichiers sélectionnés sont ceux qui sont surlignés dans la liste. On peut sélectionner plusieurs fichiers à la fois en tenant Shift, Control ou Command lorsqu’on clique sur un fichier.

+

Les fichiers marqués sont ceux avec la petite boite cochée. Il est possible de marquer les fichiers sélectionnés en appuyant sur espace.

+
+
+

Ne pas montrer les références

+

Quand ce mode est activé, les groupes de doublons sont (momentanément) brisés et les doublons sont montrés individuellement, sans leurs références. On peut agir sur les fichiers sous ce mode de la même façon que sous le mode normal.

+

L’attrait principal de ce mode est le tri. En mode normal, les groupes ne peuvent pas être brisés, et donc les résultats sont triés en fonction de leur référence. Sous ce mode spécial, le tri est fait au niveau des fichiers individuels. Il est alors possible, par exemple, de facilement marquer tous les fichiers de type « exe »:

+
    +
  • Activer le mode Ne pas montrer les références.
  • +
  • Ajouter la colonne « Type » par le menu « Colonnes ».
  • +
  • Cliquez sur la colonne Type pour changer le tri.
  • +
  • Trouvez le premier fichier avec un type « exe ».
  • +
  • Sélectionnez-le.
  • +
  • Trouvez le dernier fichier avec un type « exe ».
  • +
  • Tenez Shift et sélectionnez-le.
  • +
  • Appuyez sur espace pour marquer les fichiers sélectionnés.
  • +
+
+
+

Montrer les valeurs en tant que delta

+

Sous ce mode, certaines colonnes montreront leur valeurs relativement à la valeur de la référence du +groupe (de couleur orange, pour bien les différencier des autres valeurs). Par exemple, si un +fichier a une taille de 1.2 MB alors que la référence a une taille de 1.4 MB, la valeur affichée +sous ce mode sera -0.2 MB.

+

Les valeurs non numériques sont aussi affectées par le mode delta. Par contre, plutôt que montrer la +différence avec la valeur de référence (ce qui est impossible), elles indiquent si elles sont +pareilles en adoptant la couleur orange dans le cas ou la valeur est différent. Il est ainsi +possible de facilement identifier, par exemple, tous le doublons qui ont un nom de fichier différent +de leur référence.

+
+
+

Les deux modes ensemble

+

Quand on active ces deux modes ensemble, il est alors possible de faire de la sélection de ficher +assez avancée parce que le tri de fichier se fait alors en fonction des valeurs delta. Il devient +alors possible de, par exemple, sélectionner tous les fichiers qui ont une différence de plus de 300 +KB par rapport à leur référence, ou d’autres trucs comme ça.

+

Même chose pour les valeurs non numériques: quand les deux modes sont activés, les règles de tri +pour les valeurs non-numériques change. On commence par grouper les doublon selon si leur valeur est +orange ou non, pour ensuite procéder aux règles de tri normales. Avec ce système, il est alors +facile de, par exemple, marquer toues les doublons qui ont un nom de fichier différent de leur +référence: il suffit de trier par nom de fichier.

+
+
+

Filtrer les résultats

+

Il est possible de filtrer les résultats pour agir sur un sous-ensemble de ceux-ci, par exemple tous +les fichiers qui contiennent le mot « copie ».

+

Pour filtrer les résultats, entrer le filtrer dans le champ de la barre d’outils, puis appuyer sur +Entrée. Pour annuler le filtre, appuyez sur le X dans le champ.

+

En mode simple (le mode par défaut), ce que vous tapez est ce qui est filtré. Il n’y a qu’un +caractère spécial: *. Ainsi, si vous entrez « [*] », le filtre cherchera pour tout nom contenant +les « [ » et « ] » avec quelquechose au milieu.

+

Pour un filtrage avancé, activez Utiliser les expressions régulières pour les filtres dans les +Préférences. Votre filtre sera alors appliqué comme une expression régulière.

+

Les filtres sont dans tous les cas insensibles aux majuscules et minuscules.

+

Les expression régulière pour s’appliquer à un fichier n’ont pas besoin de correspondre au nom +entier. Une correspondance partielle suffit.

+

Vous remarquerez peut-être que ce ne sont pas tous les fichiers de vos résultats filtrés qui +s’appliquent au filtre. C’est parce que les groupes ne sont pas brisés par les filtres afin de +permettre une meilleure mise en context. Par contre, ces fichier seront en mode « Lecture seule » et +ne pourront être marqués.

+
+
+

Actions

+

Voici la liste des actions qu’il est possible d’appliquer aux résultats.

+
    +
  • Vider la liste de fichiers ignorés: Ré-initialise la liste des paires de doublons que vous avez ignorés dans le passé.
  • +
  • Exporter vers HTML: Exporte les résultats vers un fichier HTML et l’ouvre dans votre browser.
  • +
  • Envoyer marqués à la corbeille: Le nom le dit.
  • +
  • Déplacer marqués vers…: Déplace les fichiers marqués vers une destination de votre choix. La destination finale du fichier dépend de l’option « Déplacements de fichiers » dans les Préférences.
  • +
  • Copier marqués vers…: Même chose que le déplacement, sauf que c’est une copie à la place.
  • +
  • Retirer marqués des résultats: Retire les fichiers marqués des résultats. Ils ne seront donc ni effacés, ni déplacés.
  • +
  • Retirer sélectionnés des résultats: Retire les fichiers sélectionnés des résultats. Notez que si il y a des fichiers références parmi la sélection, ceux-ci sont ignorés par l’action.
  • +
  • Transformer sélectionnés en références: Prend les fichiers sélectionnés et les place à la position de référence de leur groupe respectif. Si l’action est impossible (si la référence provient d’un dossier référence), rien n’est fait.
  • +
  • Ajouter sélectionnés à la liste de fichiers ignorés: Retire les fichiers sélctionnés des résultats, puis les place dans une liste afin que les prochains scans ignorent les paires de doublons qui composaient le groupe dans lequel ces fichiers étaient membres.
  • +
  • Ouvrir sélectionné avec l’application par défaut: Ouvre le fichier sélectionné avec son application associée.
  • +
  • Ouvrir le dossier contenant le fichier sélectionné: Le nom dit tout.
  • +
  • Invoquer commande personnalisée: Invoque la commande personnalisé que vous avez définie dans les Préférences.
  • +
  • Renommer sélectionné: Renomme le fichier sélectionné après vous avoir demandé d’entrer un nouveau nom.
  • +
+

Déplacer des fichiers dans iPhoto/iTunes: Attention, quand vous déplacez des fichiers des +bibliothèques iPhoto ou iTunes, elles ne sont pas vraiment déplacées, mais copiée. Il n’y a pas +d’action de déplacement possible dans ces bibliothèques.

+
+
+

Options de suppression

+

Ces options, présentées lors de l’action de suppression de doublons, déterminent comment celle-ci +s’exécute. La plupart du temps, ces options n’ont pas a être activées.

+
    +
  • Remplacer les fichiers effacés par des liens: les fichiers supprimés seront replacés par des +liens (symlink ou hardlink) vers leur fichiers de référence respectifs. Un symlink est un +lien symbolique (qui devient caduque si l’original est supprimé) et un hardlink est un lien direct +au contenu du fichier (même si l’original est supprimé, le lien reste valide).

    +

    Sur OS X et Linux, cette fonction est supportée pleinement, mais sur Windows, c’est un peu +compliqué. Windows XP ne le supporte pas, mais Vista oui. De plus, cette fonction ne peut être +utilisée que si dupeGuru roule avec les privilèges administratifs. Ouaip, Windows c’est la joie.

    +
  • +
  • Supprimer les fichiers directement: Plutôt que d’envoyer les doublons à la corbeille, +directement les supprimer. Utiliser cette option si vous avez de la difficulté à supprimer des +fichiers (ce qui arrive quelquefois quand on travaille avec des partages réseau).

    +
  • +
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/fr/search.html b/help/fr/search.html new file mode 100644 index 00000000..7f908e9b --- /dev/null +++ b/help/fr/search.html @@ -0,0 +1,80 @@ + + + + + + + + Recherche — Documentation dupeGuru 4.0.3 + + + + + + + + + + + + + + + + + + + +
+ + +

Recherche

+
+ +

+ Veuillez activer le JavaScript pour que la recherche fonctionne. +

+
+

+ Vous pouvez effectuer une recherche au sein des documents. Saisissez les termes +de votre recherche dans le champs ci-dessous et cliquez sur "rechercher". Notez que la fonctionnalité de recherche +va automatiquement chercher l'ensemble des mots. Les pages +contenant moins de mots n'apparaîtront pas dans la liste des résultats. +

+
+ + + +
+ +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/help/fr/searchindex.js b/help/fr/searchindex.js new file mode 100644 index 00000000..e8d39cd7 --- /dev/null +++ b/help/fr/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["changelog","faq","folders","index","preferences","quick_start","reprioritize","results"],envversion:53,filenames:["changelog.rst","faq.rst","folders.rst","index.rst","preferences.rst","quick_start.rst","reprioritize.rst","results.rst"],objects:{},objnames:{},objtypes:{},terms:{"32bit":0,"64bit":0,"\u00e9crir":[1,4],"\u00e9tap":5,"\u00eate":[1,5],"\u00eatre":[1,2,3,5,7],"ale\u0161":0,"appara\u00eet":[2,7],"c\u00f4t":7,"con\u00e7u":1,"cr\u00e9":[1,4],"d\u00e9cid":[1,7],"d\u00e9faut":[2,5,7],"d\u00e9fin":[1,2,4,7],"d\u00e9marr":[2,5],"d\u00e9marrag":3,"d\u00e9mo":3,"d\u00e9monstr":1,"d\u00e9pend":7,"d\u00e9plac":[1,4,7],"d\u00e9tail":[1,7],"d\u00e9termin":[1,2,4],"d\u00e9terminent":7,"default":[0,1],"diff\u00e9renci":7,"diff\u00e9rent":[4,7],"enti\u00e8ret":4,"entr\u00e9":7,"ex\u00e9cut":7,"export":[0,7],"fa\u00e7on":7,"fen\u00eatr":[1,2,7],"final":[4,7],"for":[0,6],"g\u00e9ner":1,"id\u00e9":3,"import":[0,6],"l\u00e9ger":5,"long":0,"m\u00eam":[4,7],"new":0,"num\u00e9ro":4,"plut\u00f4t":7,"pr\u00e9f\u00e9rent":[1,3,7],"pr\u00e9sent":7,"r\u00e9f\u00e9rent":[1,2,3,4,5],"r\u00e9fer":3,"r\u00e9guli":[4,7],"r\u00e9seau":7,"r\u00e9sout":4,"r\u00e9sultat":[1,3,4,5],"recr\u00e9":4,"s\u00e9curitair":3,"s\u00e9lction":7,"s\u00e9lect":[1,3,4,7],"s\u00e9lection":[1,2,3,4,5],"sp\u00e9cial":7,"switch":0,"t\u00e2ch":7,"t\u00e4tzner":0,"t\u00e9l\u00e9charg":3,"this":[0,6],"v\u00e9rif":5,"v\u00e9rifi":[3,4],"with":[0,6],Avec:[4,7],Ces:7,Cette:[1,4],Dee:0,Does:0,Elle:2,Ils:7,Les:[1,2,3,4],Nous:1,Par:[1,4,7],Pour:[1,2,3,5,7],Que:3,Quelles:3,Sur:7,Une:7,Vous:[1,2,3,4,7],ability:0,abord:7,about:0,absolus:4,accidental:0,according:6,action:[0,1,3,5,6],activ:[0,1,7],add:[0,6],added:0,adding:0,addit:6,administr:7,adopt:7,affect:7,affected:0,affich:7,afin:[1,5,7],after:0,again:0,agir:7,aid:[5,7],ailleur:1,aim:4,ains:[4,7],ajout:[2,4,5,7],alarmed:0,algorithm:0,all:[0,6],allow:[0,6],alor:[1,7],already:0,also:0,analyzed:0,ancien:4,and:[0,6],anh:0,annoi:0,annul:7,anymor:0,anyway:0,apertur:0,app:0,appdat:1,appel:4,applied:0,appliqu:[0,2,3,4,7],appliquent:7,appui:[1,7],apres:[4,7],arbitrary:0,arch:0,archive2015:0,are:[0,6],aren:0,argument:[4,6],armenian:0,arriv:7,arrow:6,ascii:0,ask:0,assez:7,associ:7,attend:5,attent:7,attrait:7,attribut:0,attributeerror:0,aucun:1,audio:0,auss:[1,2,4,7],auto:0,automatic:0,automatically:6,autr:[2,3,7],avail:6,avanc:7,avant:7,avoid:0,avoir:[1,4,5,7],avon:1,awar:0,back:0,backend:0,bad:0,bar:[0,6],barr:[3,7],bas:[0,2,5,7],based:0,batchmod:1,becam:0,been:0,beginning:0,behavior:0,being:0,below:6,besoin:7,between:0,bibliothequ:7,bien:[1,2,3,4,7],big:0,biggest:6,bin:0,binding:0,bit:0,block:0,blu:0,boit:7,bon:[3,7],bouton:2,boutton:5,brazilian:0,bring:0,bris:7,broken:0,brows:7,bsd:0,bug:0,build:0,bump:0,bundl:0,but:[0,6],button:[0,6],byt:0,cach:0,caching:0,caduqu:7,called:0,cam:0,can:[0,6],cancel:0,cancelled:0,caracter:7,cas:[0,1,4,6,7],category:6,caus:0,caused:0,causing:0,cec:5,ceiled:0,cel:[0,1,4,7],celui:7,certain:[0,3,5,7],ceux:[2,7],champ:7,chang:[0,1,2,7],changed:0,changelog:3,chaqu:7,character:0,chemin:4,cherch:7,chines:0,chois:[2,7],choix:7,choos:0,chos:7,chosen:0,cibl:4,clear:0,clev:6,click:[0,6],cliqu:[1,2,4,5,7],cmd:0,coch:7,coco:0,collect:0,colon:[1,7],color:0,coloring:0,column:0,com:[0,1,6],combobox:6,comboboxmodel:0,comm:[1,4,7],command:[0,1,4,7],commenc:7,comment:[3,4,7],compar:4,comparaison:[1,4],comparison:0,comparon:1,compatibility:0,compl:0,complet:[0,5],compliqu:7,compos:7,comprendr:3,conf:1,config:1,configur:[0,3,5],conflit:4,confused:0,confusing:0,conserv:1,consider:4,contact:1,containing:0,conten:[4,7],content:[0,3],contenu:7,contenus:1,context:[0,7],contiennent:7,contient:[1,4],contr:[1,7],control:7,convers:0,converted:0,cop:[1,4,7],copi:7,copied:0,copy:0,cor:0,corbeil:[3,5,7],correct:[0,1],correctly:0,correspond:7,correspondr:7,corrupted:0,couldn:0,couleur:7,count:0,coupl:0,crash:0,created:0,creation:0,criter:7,criteri:[0,6],criterion:6,csv:0,custom:0,czech:0,dan:[2,3,4,5,7],dat:[0,1],debugging:0,delet:0,deleted:0,delt:[0,3,6],demand:[2,7],dependenc:0,derni:[3,7],descriptor:0,designed:0,desquel:[1,2],destin:[0,4,7],detail:0,detect:0,determin:6,detinov:0,deux:[3,4],dev:[1,4],devient:7,devr:4,dialog:[0,6],difficult:7,dir:3,direct:[1,4,7],director:0,directory:0,disabl:0,discarded:0,display:0,displayed:0,displaying:0,dit:[3,7],document:0,does:[0,6],doesn:6,doit:1,doivent:1,don:0,donc:[1,7],dossi:[3,4,5,7],doubl:[0,1,7],doublon:[2,3,4,5],drag:[0,2,5,6],dramatically:0,drop:[0,2,5,6],dropped:0,due:0,dup:[0,6],dupeguru:[0,2,4,5,6,7],duplicat:[0,3],duquel:3,during:0,dutch:0,each:[0,6],edit:[0,1],effac:[2,3,4,7],efficient:0,elegantly:0,elles:7,empty:0,enabled:0,end:[0,6],endroit:4,engin:0,ensembl:3,ensuit:[1,7],entendu:[2,7],enti:7,entre:[4,7],entrer:7,entrez:7,envoi:[3,4,5,7],eric:0,error:0,espac:[1,4,7],especially:0,essai:[3,4],even:0,exact:[0,1,5],exampl:[1,6],except:[2,4],excluded:[0,2],exclus:[0,2],exe:[4,7],execut:4,exempl:[4,7],exist:0,explicit:2,exporting:0,express:[0,4,7],ext:4,extens:0,fac:4,facil:[1,7],fact:0,fair:[3,5,7],fairwar:[0,1],fait:[1,7],fals:0,famili:1,faux:[1,5,7],featur:0,feedback:0,fer:1,fetching:0,few:0,fich:7,fichi:[2,3,4,5,7],field:0,figueiredo:0,fil:[0,4,6],filenam:[0,6],filt:0,filter:0,filtered:0,filtering:0,filtr:[1,3,4],filtrag:7,find:0,first:6,fix:0,fixed:0,focus:0,foir:3,fois:7,fold:[0,6],folder:0,followed:6,fonction:[3,7],font:0,foo:6,foobar:4,format:[0,4],found:0,frank:0,freez:0,french:0,from:0,fuzzy:0,gabriel:0,gard:3,german:0,get:[0,6],ghosting:0,github:0,glitch:0,going:0,gplv3:0,greatly:0,greek:0,gregor:0,gros:7,group:[0,2,3,4,5,6],grouping:0,gui:0,guid:3,guillemet:4,had:0,handling:0,happening:0,hard:0,hardcoded:[0,1],hardlink:[0,4,7],hardlinking:0,hardness:0,has:[0,6],haut:[1,5],hav:[0,6],having:0,help:0,her:0,hierarch:4,highest:6,hkey_current_us:1,homepag:3,hor:3,hour:0,how:0,hrant:0,html:[0,7],http:0,icon:0,identifi:7,ignor:[0,4,7],ignored:0,ignorent:7,igor:0,impossibl:[1,7],improv:0,improved:0,inaccurac:0,inconvenient:0,indent:5,index:3,indiqu:2,indiquent:7,individuel:7,info:0,initial:0,initialis:7,inod:4,insensibl:7,insensit:0,instead:0,interfac:0,internal:0,internationalized:0,into:6,introduced:0,invoc:0,involved:0,invoqu:[4,7],iphoto:[0,7],issu:0,issued:0,italian:0,item:[0,6],itun:[0,7],jam:[3,7],jet:1,job:0,joi:7,jour:3,jumpy:0,just:0,keep:0,keeping:0,keybinding:0,kind:0,korean:0,koutilel:0,kyrill:0,laquel:1,larg:0,last:0,latin:0,launch:0,launching:0,lectur:[3,7],left:6,length:0,lequel:7,library:1,licens:0,licensed:0,lien:7,lieu:[2,7],lign:[1,4],lik:0,limit:[0,3],linux:[0,1,4,7],lion:0,lir:3,lis:5,list:[0,2,6,7],littl:0,load:0,loading:0,local:1,localis:0,localiz:0,localized:0,locat:0,longest:0,lor:[1,4,7],lorsqu:[1,2,7],los:0,lost:0,lot:0,low:0,lus:4,mac:[0,1],machin:0,macos:0,mad:0,madestin:4,main:0,majuscul:7,mak:[0,6],making:0,malgr:1,manuel:4,many:[0,6],mark:0,marked:0,marking:0,marqu:[3,5],mass:0,match:0,mayb:0,mean:[0,6],medi:0,meilleur:7,membr:7,memory:0,menu:[0,2,5,6,7],merg:0,messag:0,mieux:3,might:0,milieu:7,min:0,minimum:0,minor:0,minuscul:7,mis:7,mishandling:0,mistakenly:0,mod:[0,1,3],modifi:1,moin:1,momentan:7,mondossi:4,monfichi:4,montr:[1,3],mor:[0,6],mostly:0,mot:7,mov:0,moved:0,moving:0,mp3:0,much:0,multipl:[0,7],music:[0,1],nah:0,nam:0,nasty:0,needed:6,nehyb:0,net:[0,7],niveau:7,nom:[4,7],non:[0,7],normal:[2,7],not:[0,1,7],nothing:0,notic:[0,1],nouveau:[1,7],now:0,numb:[0,6],numer:7,numeric:0,numerical:0,object:0,obsolet:0,obten:5,occasional:0,occasionally:0,occurring:0,offert:1,ohanyan:0,once:0,one:[0,6],only:[0,6],open:0,opening:0,oper:[0,4],option:[0,1,3,4,6],orang:7,order:[0,6],organis:4,original:7,ouaip:7,oui:[1,4,7],outil:[1,7],ouvr:7,overwrit:0,packaging:0,pag:[1,3],pair:[1,7],panel:0,panneau:7,paolo:0,parc:[4,7],pareil:7,parm:[2,7],part:[0,1],partag:7,partiel:7,pass:[1,2,7],path:0,pavlov:0,perm:1,permet:4,permettr:[2,3,7],permiss:[0,1],permissionerror:0,personel:4,personnalis:[4,7],personnel:4,pet:1,petit:7,petrashko:0,peu:7,peut:[1,5,7],peuvent:[2,7],peux:3,phan:0,phas:0,picked:6,picking:6,pictur:[0,1],pir:1,plac:[0,4,7],play:6,plein:7,plupart:[1,7],plus:[1,2,5,7],plusieur:7,pointent:4,pointing:6,polish:0,popping:0,posit:[0,1,2,6,7],possibility:0,possibl:[1,4,5,7],post:0,pourquoi:3,pourr:1,pourront:7,pouv:[1,2,3,7],pow:0,powerful:6,predictably:0,pref:0,preferent:0,premi:[2,3,7],prend:7,present:0,pretty:0,preventing:0,previous:0,previously:6,principal:7,prioritiz:[0,6],prioritizing:3,privileg:7,problem:[0,1],proced:[1,7],process:0,prochain:7,program:4,progress:0,propag:0,propos:3,proven:[2,3,7],provient:7,puis:[1,5,7],puiss:3,put:0,pyqt:0,python:0,quand:[4,5,7],quelquechos:7,quelquefois:7,question:3,quicklook:0,quit:0,quitting:0,quoi:3,raison:1,random:0,rapid:[2,3],rapport:7,reading:0,really:0,recent:0,recherch:[1,3,5],recommand:7,recycl:0,reduc:0,ref:0,refactoring:0,refer:0,referent:[0,2,6],refresh:0,refreshed:0,registr:[0,1],regl:[1,7],regular:0,relat:[4,7],related:0,releas:0,relev:0,reliability:0,reload:0,reloading:0,remarqu:7,rememb:0,reminder:0,remov:0,removal:0,removed:0,removing:0,remplac:[1,4,7],renam:0,renamed:0,renaming:0,renomm:7,replac:[0,7],replacing:0,report:0,reporting:0,requir:0,reset:0,respect:[1,7],responsiveness:0,rest:[5,7],restored:0,result:[0,6],retir:[1,2,5,7],retrouv:4,revamp:0,reveal:0,rewrit:0,rien:7,right:[0,6],rightmost:6,roman:0,ross:0,roul:7,rounded:0,run:0,russian:0,sam:[0,6],san:[1,3,4,7],sauf:7,sav:0,saved:0,saving:0,savoir:5,scan:[0,1,2,5,7],scann:[0,2,5,7],scanned:0,scanning:0,screen:0,second:6,section:3,seeking:0,seldom:0,select:[0,1,6],selected:[0,6],selecting:0,selon:7,send:0,sensibl:0,sent:0,separat:0,ser:[1,2,4,7],serv:1,session:1,setting:0,seuil:[1,7],seul:[4,5,7],shar:1,shelv:0,shift:[1,7],shortest:0,should:6,show:0,showing:0,sid:0,sierr:0,significantly:0,similar:0,simpl:[5,7],simplified:0,simply:0,sinc:0,situat:0,siz:[0,6],small:0,smartly:0,soft:0,softwar:[0,1],som:0,sometim:[0,6],sort:[0,1],sorting:[0,6],sous:[1,2,7],sousdossi:4,spanish:0,sparkl:0,speed:0,sphinx:0,stall:0,standard:0,start:0,started:0,starting:0,startup:0,stat:0,status:0,statut:3,sticky:0,stopped:0,stuck:0,subargu:6,subfolder:0,subsequent:0,such:0,suff:7,suivr:5,summon:6,superdiffprog:4,support:[0,1,7],suppress:3,supprim:[1,7],sure:0,surlign:7,surrogat:0,surtout:7,symbol:7,symlink:[0,7],sync:0,system:[0,1,7],systematic:0,tabl:0,taill:7,tant:3,tap:7,technical:0,tel:[0,3],temp:[1,7],temporarily:0,ten:7,termin:7,text:0,than:0,that:[0,6],the:[0,6],their:0,them:0,then:[0,6],ther:[0,6],therefor:0,thes:0,thread:0,threshold:0,through:[0,6],tie:6,ties:6,tig:0,too:0,tou:7,toujour:[1,3],tour:1,tous:[3,4,7],tout:[1,2,5,7],transform:[1,7],trash:0,travaill:7,tres:[4,7],tri:[1,6,7],trick:6,trois:2,trouv:[1,2,7],truc:7,trying:0,tweaked:0,two:6,typ:[0,1,3,4,5,7],typos:0,ubuntu:0,ukrainian:0,under:0,unicod:0,unicodeencodeerror:0,universal:0,unmaintained:0,unpaid:0,unsaved:0,updat:0,updated:0,upgrad:0,upgraded:0,upon:0,usag:0,use_regexp:0,used:[0,6],useful:0,user:[0,1,4],usernam:1,using:0,util:4,utilis:[1,2,3,4,7],valeur:3,valid:7,valu:[0,6],various:0,ver:[4,7],version:[0,3],very:0,veut:3,veux:3,victor:0,vid:[4,7],vient:1,vietnames:0,vist:[0,7],visual:0,visuel:4,vocabulair:7,voi:[2,5],voic:[1,4,5,7],votr:[4,7],voul:[1,2],vrai:[5,7],vrais:7,want:0,warning:0,was:0,wasn:0,way:0,web:0,weighting:0,wel:0,wer:[0,6],when:[0,6],wher:[0,6],which:[0,6],whil:0,whol:0,will:[0,6],win:6,window:[0,1,7],woes:0,wond:0,word:0,work:0,working:0,would:0,wouldn:0,writabl:0,wrong:[0,6],www:0,xhtml:0,yeah:0,you:[0,6],your:[0,6],yur:0},titles:["Changelog","Foire aux questions","S\u00e9lection de dossiers","Aide dupeGuru","Pr\u00e9f\u00e9rences","D\u00e9marrage rapide","Re-Prioritizing duplicates","R\u00e9sultats"],titleterms:{"d\u00e9marrag":5,"d\u00e9mo":1,"pr\u00e9f\u00e9rent":4,"r\u00e9f\u00e9rent":7,"r\u00e9sultat":7,"s\u00e9curitair":1,"s\u00e9lect":2,"s\u00e9lection":7,"v\u00e9rifi":7,Les:7,Que:1,Quelles:1,action:7,aid:3,and:3,appliqu:1,appnam:[],autr:1,barr:1,certain:1,changelog:0,configur:1,corbeil:1,dan:1,delt:7,deux:7,dir:1,dit:1,dossi:[1,2],doublon:[1,7],dupeguru:[1,3],duplicat:6,duquel:1,effac:1,ensembl:7,envoi:1,essai:1,fair:1,fichi:1,filtr:7,foir:1,group:[1,7],hor:1,indic:3,jam:1,limit:1,marqu:[1,7],mieux:1,mod:7,montr:7,option:7,peux:1,pourquoi:1,prioritizing:6,propos:7,proven:1,question:1,quoi:1,rapid:5,sommair:1,statut:1,suppress:7,tabl:3,tant:7,tous:1,typ:2,valeur:7,veut:1,veux:1}}) \ No newline at end of file diff --git a/help/hy/.buildinfo b/help/hy/.buildinfo new file mode 100644 index 00000000..a9c3179c --- /dev/null +++ b/help/hy/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: a874776587ce2da814c4810262a52987 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/help/hy/.doctrees/changelog.doctree b/help/hy/.doctrees/changelog.doctree new file mode 100644 index 00000000..c6149ee6 Binary files /dev/null and b/help/hy/.doctrees/changelog.doctree differ diff --git a/help/hy/.doctrees/environment.pickle b/help/hy/.doctrees/environment.pickle new file mode 100644 index 00000000..f48a116e Binary files /dev/null and b/help/hy/.doctrees/environment.pickle differ diff --git a/help/hy/.doctrees/faq.doctree b/help/hy/.doctrees/faq.doctree new file mode 100644 index 00000000..91a33769 Binary files /dev/null and b/help/hy/.doctrees/faq.doctree differ diff --git a/help/hy/.doctrees/folders.doctree b/help/hy/.doctrees/folders.doctree new file mode 100644 index 00000000..26419a16 Binary files /dev/null and b/help/hy/.doctrees/folders.doctree differ diff --git a/help/hy/.doctrees/index.doctree b/help/hy/.doctrees/index.doctree new file mode 100644 index 00000000..3f8382bc Binary files /dev/null and b/help/hy/.doctrees/index.doctree differ diff --git a/help/hy/.doctrees/preferences.doctree b/help/hy/.doctrees/preferences.doctree new file mode 100644 index 00000000..da5486f8 Binary files /dev/null and b/help/hy/.doctrees/preferences.doctree differ diff --git a/help/hy/.doctrees/quick_start.doctree b/help/hy/.doctrees/quick_start.doctree new file mode 100644 index 00000000..9ab3cae0 Binary files /dev/null and b/help/hy/.doctrees/quick_start.doctree differ diff --git a/help/hy/.doctrees/reprioritize.doctree b/help/hy/.doctrees/reprioritize.doctree new file mode 100644 index 00000000..8fd43437 Binary files /dev/null and b/help/hy/.doctrees/reprioritize.doctree differ diff --git a/help/hy/.doctrees/results.doctree b/help/hy/.doctrees/results.doctree new file mode 100644 index 00000000..83cbb8bb Binary files /dev/null and b/help/hy/.doctrees/results.doctree differ diff --git a/help/hy/_sources/changelog.rst.txt b/help/hy/_sources/changelog.rst.txt new file mode 100644 index 00000000..b1fc6f65 --- /dev/null +++ b/help/hy/_sources/changelog.rst.txt @@ -0,0 +1,705 @@ +:tocdepth: 1 + +Changelog +========= + +**About the word "crash":** When reading this changelog, you might be alarmed at the number of fixes +for "crashes". Be aware that when the word "crash" is used here, it refers to "soft crashes" which +don't cause the application to quit. You simply get an error window that asks you if you want to +send the crash report to Hardcoded Software. Crashes that cause the application to quit are called +"hard crashes" in this changelog. + + +4.0.3 (2016-11-24) +---------------------- + +* Add new picture cache backend: shelve +* Make shelve picture cache backend the active one on MacOS to fix `#394 `__ more + elegantly. [cocoa] +* Remove Sparkle (auto-updates) due to technical limitations. [cocoa] + + +4.0.2 (2016-10-09) +---------------------- + +* Fix systematic crash in Picture Mode under MacOS Sierra. (`#394 `__) +* No change for Linux. Just keeping version in sync. + + +4.0.1 (2016-08-24) +---------------------- + +* Add Greek localization, by Gabriel Koutilellis. (`#382 `__) +* Fix localization base path. [qt] (`#378 `__) +* Fix broken load results dialog. [qt] +* Fix crash on load results. [cocoa] (`#380 `__) +* Save preferences more predictably. [qt] (`#379 `__) +* Fix picture mode's fuzzy block scanner threshold. (`#387 `__) + + +4.0.0 (2016-07-01) +---------------------- + +* Merge Standard, Music and Picture editions in the same application! +* Improve documentation. (`#294 `__) +* Add Polish, Korean, Spanish and Dutch localizations. +* qt: Fix wrong use_regexp option propagation to core. (`#295 `__) +* qt: Fix progress window mistakenly showing up on startup. (`#357 `__) +* Bump Python requirement to v3.4. +* Bump OS X requirement to 10.8 +* Drop Windows support, maybe temporarily. + `Details `__-11-01>`_ +* cocoa: Drop iPhoto, Aperture and iTunes support. Was unmaintained and obsolete. +* Drop "Audio Contents" scan type. Was confusing and seldom useful. +* Change license to GPLv3 + + +3.9.1 (2014-10-17) +---------------------- + +* Fixed ``AttributeError: 'ComboboxModel' object has no attribute 'reset'``. [Linux, Windows] (`#254 `__) +* Fixed ``PermissionError`` on saving results. (`#266 `__) +* Fixed a build problem introduced by Sphinx 1.2.3. +* Updated German localisation, by Frank Weber. + + +3.9.0 (2014-04-19) +---------------------- + +* This is mostly a dependencies upgrade. +* Upgraded to Python 3.3. +* Upgraded to Qt 5. +* Minimum Windows version is now Windows 7 64bit. +* Minimum Ubuntu version is now 14.04. +* Minimum OS X version is now 10.7 (Lion). +* ... But with a couple of little improvements. +* Improved documentation. +* Overwrite subfolders' state when setting states in folder dialog (`#248 `__) +* The error report dialog now brings the user to Github issues. + + +3.8.0 (2013-12-07) +---------------------- + +* Disable symlink/hardlink deletion option when not relevant. (`#247 `__) +* Make Cmd+A select all folders in the Folder Selection dialog. [Mac] (`#228 `__) +* Make non-numeric delta comparison case insensitive. (`#239 `__) +* Fix surrogate-related UnicodeEncodeError on CSV export. (`#210 `__) +* Fixed crash on Dupe Count sorting with Delta + Dupes Only. (`#238 `__) +* Improved documentation. +* Important internal refactorings. +* Dropped Ubuntu 12.04 and 12.10 support. +* Removed the fairware dialog (`More Info `__). + + +3.7.1 (2013-08-19) +---------------------- + +* Fixed folder scan type, which was broken in v3.7.0. + + +3.7.0 (2013-08-17) +---------------------- + +* Improved delta values to support non-numerical values. (`#213 `__) +* Improved the Re-Prioritize dialog's UI. (`#224 `__) +* Added hardlink/symlink support on Windows Vista+. (`#220 `__) +* Dropped 32bit support on Mac OS X. +* Added Vietnamese localization by Phan Anh. + + +3.6.1 (2013-04-28) +---------------------- + +* Improved "Make Selection Reference" to make it clearer. (`#222 `__) +* Improved "Open Selected" to allow opening more than one file at once. (`#142 `__) +* Fixed a few typos here and there. (`#216 `__ `#225 `__) +* Tweaked the fairware dialog (`More Info `__). +* Added Arch Linux packaging +* Added a 64-bit build for Windows. +* Improved Russian localization by Kyrill Detinov. +* Improved Brazilian localization by Victor Figueiredo. + + +3.6.0 (2012-08-08) +---------------------- + +* Added "Export to CSV". (`#189 `__) +* Added "Replace with symlinks" to complement "Replace with hardlinks". [Mac, Linux] (`#194 `__) +* dupeGuru now tells how many duplicates were affected after each re-prioritization operation. (`#204 `__) +* Added Longest/Shortest filename criteria in the re-prioritize dialog. (`#198 `__) +* Fixed result table cells which mistakenly became writable in v3.5.0. [Mac] (`#203 `__) +* Fixed "Rename Selected" which was broken since v3.5.0. [Mac] (`#202 `__) +* Fixed a bug where "Reset to Defaults" in the Columns menu wouldn't refresh menu items' marked state. +* Added Brazilian localization by Victor Figueiredo. + + +3.5.0 (2012-06-01) +---------------------- + +* Added a Deletion Options panel. +* Greatly improved memory usage for big scans. +* Added a keybinding for the filter field. (`#182 `__) [Mac] +* Upgraded minimum requirements for Ubuntu to 12.04. + + +3.4.1 (2012-04-14) +---------------------- + +* Fixed the "Folders" scan type. [Mac] +* Fixed localization issues. [Windows, Linux] + + +3.4.0 (2012-03-29) +---------------------- + +* Improved results window UI. [Windows, Linux] +* Added a dialog to edit the Ignore List. +* Added the ability to sort results by "marked" status. +* Fixed "Open with default application". (`#190 `__) +* Fixed a bug where there would be a false reporting of discarded matches. (`#195 `__) +* Fixed various localization glitches. +* Fixed hard crashes on crash reporting. (`#196 `__) +* Fixed bug where the details panel would show up at inconvenient places in the screen. [Windows, Linux] + + +3.3.3 (2012-02-01) +---------------------- + +* Fixed crash on adding some folders. [Mac OS X] +* Added Ukrainian localization by Yuri Petrashko. + + +3.3.2 (2012-01-16) +---------------------- + +* Fixed random hard crashes (yeah, again). [Mac OS X] +* Fixed crash on Export to HTML. [Windows, Linux] +* Added Armenian localization by Hrant Ohanyan. +* Added Russian localization by Igor Pavlov. + + +3.3.1 (2011-12-02) +---------------------- + +* Fixed a couple of nasty crashes. + + +3.3.0 (2011-11-30) +---------------------- + +* Added multiple-selection in folder selection dialog for a more efficient folder removal. (`#179 `__) +* Fixed a crash in the prioritize dialog. (`#178 `__) +* Fixed a bug where mass marking with a filter would mark more than filtered duplicates. (`#181 `__) +* Fixed random hard crashes. [Mac OS X] (`#183 `__ `#184 `__) +* Added Czech localization by Aleš Nehyba. +* Added Italian localization by Paolo Rossi. + + +3.2.1 (2011-10-02) +---------------------- + +* Fixed a couple of broken action bindings from v3.2.0. + + +3.2.0 (2011-09-27) +---------------------- + +* Added duplicate re-prioritization dialog. (`#138 `__) +* Added font size preference for duplicate table. (`#82 `__) +* Added Quicklook support. [Mac OS X] (`#21 `__) +* Improved behavior of Mark Selected. (`#139 `__) +* Improved filename sorting. (`#169 `__) +* Added Chinese (Simplified) localization by Eric Dee. +* Tweaked the fairware system. +* Upgraded minimum requirements to OS X 10.6 and Ubuntu 11.04. + + +3.1.2 (2011-08-25) +---------------------- + +* Fixed a bug preventing the Folders scan from working. (`#172 `__) + + +3.1.1 (2011-08-24) +---------------------- + +* Added German localization by Gregor Tätzner. +* Improved OS X Lion compatibility. [Mac OS X] +* Made the file collection phase cancellable. (`#168 `__) +* Fixed glitch in folder window upon selecting a folder state. [Windows, Linux] (`#165 `__) +* Fixed a text coloring glitch in the results. (`#156 `__) +* Fixed glitch in the sorting feature of the Folder column. (`#161 `__) +* Make sure that saved results have the ".dupeguru" extension. [Linux] (`#157 `__) + + +3.1.0 (2011-04-16) +---------------------- + +* Added the "Folders" scan type. (`#89 `__) +* Fixed a couple of crashes. (`#140 `__ `#149 `__) + + +3.0.2 (2011-03-16) +---------------------- + +* Fixed crash after removing marked dupes. (`#140 `__) +* Fixed crash on error handling. [Windows] (`#144 `__) +* Fixed crash on copy/move. [Windows] (`#148 `__) +* Fixed crash when launching dupeGuru from a very long folder name. [Mac OS X] (`#119 `__) +* Fixed a refresh bug in directory panel. (`#153 `__) +* Improved reliability of the "Send to Trash" operation. [Linux] +* Tweaked Fairware reminders. + + +3.0.1 (2011-01-27) +---------------------- + +* Restored the context menu which had been broken in 3.0.0. [Mac OS X] (`#133 `__) +* Fixed a bug where an "unsaved results" warning would be issued on quit even with empty results. (`#134 `__) +* Removed focus from the cancel button in the progress dialog to avoid accidental cancellations. [Mac OS X] (`#135 `__) +* Folders added through drag and drop are added to the recent folders list. (`#136 `__) +* Added a debugging mode. (`#132 `__) +* Fixed french localization glitches. + + +3.0.0 (2011-01-24) +---------------------- + +* Re-designed the UI. (`#129 `__) +* Internationalized dupeGuru and localized it to french. (`#32 `__) +* Changed the format of the help file. (`#130 `__) + + +2.12.3 (2011-01-01) +---------------------- + +* Fixed bug causing results to be corrupted after a scan cancellation. (`#120 `__) +* Fixed crash when fetching Fairware unpaid hours. (`#121 `__) +* Fixed crash when replacing files with hardlinks. (`#122 `__) + + +2.12.2 (2010-10-05) +---------------------- + +* Fixed delta column colors which were broken since 2.12.0. +* Fixed column sorting crash. (`#108 `__) +* Fixed occasional crash during scan. (`#106 `__) + + +2.12.1 (2010-09-30) +---------------------- + +* Re-licensed dupeGuru to BSD and made it `Fairware `__. + + +2.12.0 (2010-09-26) +---------------------- + +* Improved UI with a little revamp. +* Added the possibility to place hardlinks to references after having deleted duplicates. [Mac OS X, Linux] (`#91 `__) +* Added an option to ignore duplicates hardlinking to the same file. [Mac OS X, Linux] (`#92 `__) +* Added multiple selection in the "Add Directory" dialog. [Mac OS X] (`#105 `__) +* Fixed a bug preventing drag & drop from working in the Directories panel. [Windows, Linux] + + +2.11.1 (2010-08-26) +---------------------- + +* Fixed HTML exporting which was broken in 2.11.0. + + +2.11.0 (2010-08-18) +---------------------- + +* Added the ability to save results (and reload them) at arbitrary locations. +* Improved the way reference files in dupe groups are chosen. (`#15 `__) +* Remember size/position of all windows between launches. (`#102 `__) +* Fixed a bug sometimes preventing dupeGuru from reloading previous results. +* Fixed a bug sometimes causing the progress dialog to be stuck there. [Mac OS X] (`#103 `__) +* Removed the Creation Date column, which wasn't displaying the correct value anyway. (`#101 `__) + + +2.10.1 (2010-07-15) +---------------------- + +* Fixed a couple of crashes. (`#95 `__, `#97 `__, `#100 `__) + + +2.10.0 (2010-04-13) +---------------------- + +* Improved error messages when files can't be sent to trash, moved or copied. +* Added a custom command invocation action. (`#12 `__) +* Filters are now applied on whole paths. (`#4 `__) + + +2.9.2 (2010-02-10) +---------------------- + +* dupeGuru is now 64-bit on Mac OS X! +* Fixed a crash upon quitting when support folder is not present. (`#83 `__) +* Fixed a crash during sorting. (`#85 `__) +* Fixed selection glitches, especially while renaming. (`#93 `__) + + +2.9.1 (2010-01-13) +---------------------- + +* Improved memory usage for Contents scans. (`#75 `__) +* Improved scanning speed when ref directories are involved. (`#77 `__) +* Show a message dialog at the end of the scan if no duplicates are found. (`#81 `__) +* Fixed a bug sometimes causing the small files threshold pref to be ignored. [Mac OS X] (`#75 `__) + + +2.9.0 (2009-11-03) +---------------------- + +* Significantly improved speed and memory usage of big contents-based scans. +* Added drag & drop support in the Directories panel. (`#9 `__) +* Fixed a bug causing dupeGuru to be confused if a scanned file was moved during the scan. (`#72 `__) +* Dropped support for Mac OS X 10.4 (Tiger) + + +2.8.2 (2009-10-14) +---------------------- + +* Improved directory selection in the Directories panel (Windows). (`#56 `__) +* Fixed a bug preventing dupeGuru from starting on certain machines (Windows). (`#68 `__) +* Fixed a crash during very big scans. (`#70 `__) + + +2.8.1 (2009-10-02) +---------------------- + +* Fixed crash with filtering when regular expressions were enabled. (`#60 `__) +* Fixed crash when setting directories' state. (Mac OS X) (`#66 `__) +* Fixed crash with Make Reference when certain filters are applied. (Mac OS X) (`#55 `__) +* Improved error handling during delete/move/copy actions. (`#62 `__ `#65 `__) + + +2.8.0 (2009-09-07) +---------------------- + +* Added support for all kinds of bundle (not just applications) (Mac OS X) (`#11 `__) +* Re-introduced the Export to XHTML feature to Windows. (`#14 `__) +* Improved Export to XHTML speed. (`#14 `__) +* Improved Contents scanning speed for large files. (`#33 `__) +* Improved the grouping algorithm to reduce the number of discarded files in non-exact scans. (`#51 `__) +* Stopped showing the same file on the 2 sides of the details panel when a ref file is selected. (`#50 `__) +* Fixed crashes in the Directories panel. (`#46 `__) + + +2.7.3 (2009-06-20) +---------------------- + +* Fixed bugs with selection being jumpy during "Make Reference" actions and Power Marker + switches. (`#3 `__) +* Fixed crash happening when a file with non-roman characters couldn't be analyzed. (`#30 `__) +* Fixed crash sometimes happening during the file collection phase in scanning. (`#38 `__) +* Restored double-click and right-click behavior lost in the PyQt move (Windows). (`#34 `__ `#35 `__) + + +2.7.2 (2009-06-10) +---------------------- + +* Fixed an occasional crash on Copy/Move operations. (`#16 `__) +* Added automatic exclusion for sensible folders (like system folders). (`#20 `__) +* Fixed an occasional crash when application files were part of the results (Mac OS X). (`#25 `__) + + +2.7.1 (2009-05-29) +---------------------- + +* Fixed a bug causing crashes when having application files in the results. +* Fixed a bug causing a GUI freeze at the beginning of a scan with a lot of files. +* Fixed a bug that sometimes caused a crash when an action was cancelled, and then started again. + + +2.7.0 (2009-05-25) +---------------------- + +* Converted the Windows GUI to Qt. +* Improved the reliability of the scanning process. + + +2.6.1 (2009-03-27) +---------------------- + +* **Fixed** an occasional crash caused by permission issues. +* **Fixed** a bug where the "X discarded" notice would show a too large number of discarded + duplicates. + + +2.6.0 (2008-09-10) +---------------------- + +* **Added** a small file threshold preference. +* **Added** a notice in the status bar when matches were discarded during the scan. +* **Improved** duplicate prioritization (smartly chooses which file you will keep). +* **Improved** scan progress feedback. +* **Improved** responsiveness of the user interface for certain actions. + + +2.5.4 (2008-08-10) +---------------------- + +* **Improved** the speed of results loading and saving. +* **Fixed** a crash sometimes occurring during duplicate deletion. + + +2.5.3 (2008-07-08) +---------------------- + +* **Improved** unicode handling for filenames. dupeGuru will now find a lot more duplicates if your files have non-ascii characters in it. +* **Fixed** "Clear Ignore List" crash in Windows. + + +2.5.2 (2008-01-10) +---------------------- + +* **Improved** the handling of low memory situations. +* **Improved** the directory panel. The "Remove" button changes to "Put Back" when an excluded directory is selected. +* **Improved** scan, delete and move speed in situations where there were a lot of duplicates. +* **Fixed** occasional crashes when moving bundles (such as .app files). +* **Fixed** occasional crashes when moving a lot of files at once. + + +2.5.1 (2007-11-22) +---------------------- + +* **Added** the "Remove empty folders" option. +* **Fixed** results load/save issues. +* **Fixed** occasional status bar inaccuracies when the results are filtered. + + +2.5.0 (2007-09-15) +---------------------- + +* **Added** post scan filtering. +* **Fixed** issues with the rename feature under Windows +* **Fixed** some user interface annoyances under Windows + + +2.4.8 (2007-04-14) +---------------------- + +* **Improved** UI responsiveness (using threads) under Mac OS X. +* **Improved** result load/save speed and memory usage. + + +2.4.7 (2007-03-10) +---------------------- + +* **Fixed** a "bad file descriptor" error occasionally popping up. +* **Fixed** a bug with non-latin directory names. + + +2.4.6 (2007-02-10) +---------------------- + +* **Added** Re-orderable columns. In fact, I re-added the feature which was lost in the C# conversion in 2.4.0 (Windows). +* **Changed** the behavior of the scanning engine when setting the hardness to 100. It will now only match files that have their words in the same order. +* **Fixed** a bug with all the Delete/Move/Copy actions with certain kinds of files. + + +2.4.5 (2007-01-11) +---------------------- + +* **Fixed** a bug with the Move action. + + +2.4.4 (2007-01-07) +---------------------- + +* **Fixed** a "ghosting" bug. Dupes deleted by dupeGuru would sometimes come back in subsequent scans (Windows). +* **Fixed** bugs sometimes making dupeGuru crash when marking a dupe (Windows). +* **Fixed** some minor visual glitches (Windows). + + +2.4.3 (2006-12-08) +---------------------- + +* **Fixed** a mishandling of ".app" files (OS X). +* **Fixed** a bug preventing files from "reference" directories to be displayed in blue in the results (Windows). +* **Fixed** a bug preventing some files to be sent to the recycle bin (Windows). +* **Fixed** a bug in the packaging preventing certain Windows configurations to start dupeGuru at all. + + +2.4.2 (2006-11-18) +---------------------- + +* **Fixed** a bug with directory states. + + +2.4.1 (2006-11-15) +---------------------- + +* **Fixed** a bug causing the ignore list not to be saved. +* **Fixed** a bug sometimes making delete and move operations stall. + + +2.4.0 (2006-11-10) +---------------------- + +* **Changed** the Windows interface. It is now .NET based. +* **Added** an auto-update feature to the windows version. +* **Changed** the way power marking works. It is now a mode instead of a separate window. +* **Changed** the "Size (MB)" column for a "Size (KB)" column. The values are now "ceiled" instead of rounded. Therefore, a size "0" is now really 0 bytes, not just a value too small to be rounded up. It is also the case for delta values. +* **Removed** the min word length/count options. These came from Mp3 Filter, and just aren't used anymore. Word weighting does pretty much the same job. + + +2.3.4 (2006-11-07) +---------------------- + +* **Improved** speed and memory usage of the scanning engine, again. Does it mean there was a lot of improvements to be made? Nah... + + +2.3.3 (2006-11-02) +---------------------- + +* **Improved** speed and memory usage of the scanning engine, especially when the scan results in a lot of duplicates. +* Now I wonder if Sparkle is going to work well... + + +2.3.2 (2006-10-16) +---------------------- + +* **Added** an auto-update feature in the Mac OS X version (with Sparkle). +* **Fixed** a bug preventing some duplicate reports to be created correctly under Windows. + + +2.3.1 (2006-10-02) +---------------------- + +* **Fixed** a bug preventing some duplicates to be found, especially when scanning lots of files. + + +2.3.0 (2006-09-22) +---------------------- + +* **Added** XHTML export feature. + + +2.2.10 (2006-08-31) +---------------------- + +* **Added** sticky columns. +* **Fixed** an issue with file caching between scans. +* **Fixed** an issue preventing some duplicates from being deleted/moved/copied. + + +2.2.9 (2006-08-27) +---------------------- + +* **Fixed** an issue with ignore list and unicode. +* **Fixed** an issue with file attribute fetching sometimes causing dupeGuru to crash. +* **Fixed** an issue in the directories panel under Windows. + + +2.2.8 (2006-08-17) +---------------------- + +* **Fixed** an issue in the duplicate seeking engine preventing some duplicates to be found. + + +2.2.7 (2006-08-12) +---------------------- + +* **Improved** unicode support. +* **Improved** the "Reveal in Finder" ("Open Containing Folder" in Windows) feature so it selects the file in the folder it opens. + + +2.2.6 (2006-08-07) +---------------------- + +* **Improved** the ignore list system. +* dupeGuru is now a Universal application on Mac OS X. + + +2.2.5 (2006-07-26) +---------------------- + +* **Improved** application (.app) dupe detection on Mac OS X. +* **Fixed** an issue that occasionally made dupeGuru crash on startup. + + +2.2.4 (2006-06-27) +---------------------- + +* **Fixed** an issue with Move and Copy features. + + +2.2.3 (2006-06-15) +---------------------- + +* **Improved** duplicate scanning speed. +* **Added** a warning that a file couldn't be renamed if a file with the same name already exists. + + +2.2.2 (2006-06-07) +---------------------- + +* **Added** "Rename Selected" feature. +* **Fixed** some minor issues with "Reload Last Results" feature. +* **Fixed** ignore list issues. + + +2.2.1 (2006-05-22) +---------------------- + +* **Fixed** occasional progress bar woes under Windows. +* **Fixed** a bug in the registration system under Windows. +* Nothing has been changed in the Mac OS X version, but I want to keep version in sync. + + +2.2.0 (2006-05-10) +---------------------- + +* **Added** destination path re-creation options. +* **Added** an ignore list. +* **Changed** the main icon. +* **Improved** dramatically the delta values feature. + + +2.1.2 (2006-04-18) +---------------------- + +* **Added** the "Match similar words" option. +* **Fixed** Power marking issues under Mac. + + +2.1.1 (2006-04-14) +---------------------- + +* **Added** the "Display delta values" option. +* **Improved** Power marking sorting speed under Mac. +* **Fixed** Power marking sorting issues. + + +2.1.0 (2006-04-03) +---------------------- + +* **Added** the Power Marker feature. +* **Fixed** a column sorting bug. The results would sometimes lose their sort order. +* **Fixed** a bug with the Make Reference feature. The results sometimes wasn't correctly refreshed after the reference switch. + + +2.0.1 (2006-03-23) +---------------------- + +* **Fixed** an issue occasionally occurring when trying to reload results from removable media that is no longer present. + + +2.0.0 (2006-03-17) +---------------------- + +* Complete rewrite. +* Now runs on Mac OS X. + + +1.0.0 (2004-09-24) +---------------------- + +* Initial release. + diff --git a/help/hy/_sources/faq.rst.txt b/help/hy/_sources/faq.rst.txt new file mode 100644 index 00000000..eeb42dea --- /dev/null +++ b/help/hy/_sources/faq.rst.txt @@ -0,0 +1,115 @@ +Հաճախ Տրվող Հարցեր +========================== + +.. topic:: Ի՞նչ է dupeGuru-ը: + + .. only:: edition_se + + dupeGuru-ն ծրագիր է, որ գտնում է համակարգչի ֆայլերի կրկնօրինակները: Այն կարող է ստուգել ըստ ֆայլի անվան կամ բովանդակության: Ֆայլի անվամբ փնտրման հնարավորությունը ոչ ճշգրիտ համընկնումներ է տալիս երբեմն: Շատ ժամանակ անունները նույնն են, բայց ֆայլերը տարբեր են: + + .. only:: edition_me + + dupeGuru Music Edition-ը ծրագիր է, որ գտնում է համակարգչի երաժշտական ֆայլերի կրկնօրինակները: Այն կարող է հիմնվել ֆայլի անունները ստուգելու վրա՝ ըստ կցապիտակների և բովանդակության: Ֆայլի անունների և կցապիտակների ստուգումը ոչ ճշգրիտ ալգորիթմ է, քանզի այն կարող է գտնել համընկնումներ, որոնք իրականում նույնը չեն: + + .. only:: edition_pe + + dupeGuru Picture Edition (PE՝ կարճ)-ը ծրագիր է, որ գտնում է համակարգչի նկարների ֆայլերի կրկնօրինակները: Այն կարող է գտնել ոչ միայն ճշգրիտ համընկնումները, այլև այն կարող է գտնել տարբեր որակի և տեսակի նկարների (PNG, JPG, GIF և այլն...) համընկնումներ: + +.. topic:: Ի՞նչն է այս ծրագիրը առանձնացնում մյուս նմանատիպ ծրագրերից: + + Ստուգելու համակարգը չափազանց նուրբ է: Կարող եք ինքներդ հարմարեցնել այն՝ ստանալու համար այն արդյունքը, ինչը որ Ձեզ պետք է: Կարող եք լրացուցիչ կարդալ այս մասին dupeGuru-ի կարգավորման ընտրանքներում՝ :doc:`Կարգավորումների էջում `: + +.. topic:: Ո՞րքանով է անվտանգ օգտագործելու dupeGuru-ը: + + Շատ անվտանգ է: dupeGuru-ը նախագծվել է՝ համոզված լինելու համար, որ Դուք չջնջեք այն ֆայլերը, որոնք չպետք է ջնջեք: Նախ, կա հղմամբ համակարգային թղթապանակ, որը հնարավորություն է տալիս Ձեզ որոշելու թղթապանակներ, որտեղ Դուք բացարձակ **չեք** ցանկանում, որ dupeGuru-ն հնարավորություն տա Ձեզ ջնջելու ֆայլերը այստեղից, և ապա կա խմբի հղմամբ համակարգային համակարգ, որը համոզմունք է ստեղծում, որ Դուք **միշտ** պետք է պահեք գոնե մեկ անդամ կրկնօրինակվող խմբի: + +.. topic:: Ո՞րոն եք dupeGuru-ի լիցենզիայի սահմանափակումները: + + Փորձնական եղանակում, Դուք կարող եք միայն կատարել գործողություններ 10 կրկնօրինակների հետ միաժամանակ: Ծրագրի + `Անվճար տարբերակում `_ mode, այնուհանդերձ չկան էական սահմանափակումներ: + +.. topic::Ջնջելու համար նշելու դաշտի պատուհանը ակտիվ չէ: Ի՞նչ անել: + + Չեք կարող նշել հղումը (Առաջին ֆայլը) կրկնօրինակվող խմբի: Այնուհանդերձ, ինչ կարող եք Դուք անել առաջ մղելու համար կրկնօրինակվող ֆայլը հղմանը: Այսպիսով, եթե ֆայլը ցանկանում եք նշել որպես հղում, ընտրեք կրկնօրինակվող ֆայլը խմբից, որը ցանկանում եք տանել հղման մեջ, և սեղմեք **Գործողություններ-->Դարձնել ընտրվածը հղում**: Եթե հղվող ֆայլը հղման թղթապանակից է (ֆայլի անունը գրված է կապույտ տառերով), Դուք չեք կարող ջնջել այն հղման դիրքից: + +.. topic:: Ես ունեմ թղթապանակ, որտեղից ես իրապես չեմ ցանկանում ջնջել ֆայլեր: + + Եթե Դուք ցանկանում եք համոզված լինել, որ dupeGuru-ն երբեք չի ջնջի ֆայլ կոնկրետ թղթապանակից, համոզված եղեք, որ տվել եք կարգը **Հղման** :doc:`folders`: + +.. topic:: Ի՞նչ է սա '(X վնասված)'՝ նշված դրության տողում: + + Որոշ դեպքերում, որոշ համընկնումներ ներառված չեն վերջնական արդյունքում երկրորդական պատճառներով: Եկեք նայենք կոնկրետ օրինակի վրա: Մենք ունենք 3 ֆայլ. A, B և C: Մենք ստուգում ենք այն՝ օգտագործելով ֆիլտրի ցածր մակարդակով: Ստուգիչը արդեն որոշել է, որ A համընկնումները B-ի, A-ի համընկնումները C-ին, բայց B-ն **չի** համընկնում C-ին: Այստեղ dupeGuru-ն ունի մի շարք խնդիրներ: Այն չի կարող ստեղծել կրկնօրինակվող խումբ A, B և C իրենում, որովհետև ոչ բոլոր ֆայլերն են խմբում համընկնում միմյանց: Այն կարող է ստեղծել 2 խումբ. մեկ A-B խումբ և ապա մեկ A-C խումբ, բայց այն չի լինի՝ անվտանգության նկատառումներից ելնելով: Եկեք մտածենք սրա մասին. Եթե B-ն չի համընկնում C-ին, հնարավոր է դա նշանակում է, որ անգամ B, C կամ երկուսն էլ իրականում կրկնօրինակներ չեն: Եթե այնտեղ լինեն 2 խմբեր (A-B և A-C), ապա Դուք պետք է ջնջեք B-ն և C-ն: Եթե դրանցից մեկը կրկնօրինակ չէ, ապա դա այն չէ, ինչը որ Ձեզ պետք է, այնպես չէ՞: Այսպիսով, ինչ dupeGuru չի մի դեպքում նման սրան՝ բացառելով A-C համընկնումը (և ավելացնում է տեղեկացում դրության տողում): Այսպիսով, եթե Դուք ջնջեք B-ն և վերսկսեք ստուգումը, ապա կունենք A-C համընկնում հաջորդ արդյունքներում: + +.. topic:: Ես ցանկանում եմ նշել բոլոր ֆայլերը որոշված թղթապանակից: Ի՞նչ կարող եմ ես անել: + + Միացնել :doc:`Միայն Սխալները ` եղանակը և սեղմեք թղթապանակի սյանը՝ դասավորելու համար կրկնօրինակները ըստ թղթապանակների: Հետագայում հեշտ կլինի ընտրելու բոլոր կրկնօրինակները նույն թղթապանակից և ապա սեղմեք Space՝ ընտրելու ահմար բոլոր կրկնօրինակները: + +.. only:: edition_se or edition_pe + + .. topic:: Ես ցանկանում եմ հեռացնել բոլոր ֆայլերը, որոնք 300 ԿԲ-ից ավելի են հղվող ֆայլից: Ի՞նչ կարող եմ ես անել: + + * Միացնել :doc:`Միայն Սխալները ` եղանակում: + * Միացնել **Դելտա նշանակությունները** եղանակը: + * Սեղմեք "Չափը" սյանը՝ դասավորելու համար արդյունները ըստ չափի; + * Ընտրեք բոլոր կրկնօրինակները՝ -300-ից ցածր: + * Սեղմեք **Ջնջել ընտրվածը Արդյունքներից**: + * Ընտրեք բոլոր կրկնօրինակերը, որոնք մեծ են 300-ից: + * Սեղմեք **Ջնջել ընտրվածները Արդյունքներից**: + + .. topic:: Ես ցանկանում եմ դարձնել վերջին փոփոխված ֆայլերը հղման ֆայլեր: Ի՞նչ կարող եմ ես անել: + + * Միացնել :doc:`Միայն Սխալները ` եղանակում: + * Միացնել **Դելտա նշանակությունները** եղանակը: + * Սեղմեք "Ըստ փոփոխության" սյանը՝ արդյունքները ըստ փոփոխման դասավորելու համար: + * Սեղմեք "Ըստ փոփոխության" սյանը՝ կրկնելու համար դասավորման կարգը: + * Ընտրել բոլոր կրկնօրինակները 0-ից բարձր: + * Սեղմեք **Դարձնել ընտրվածը հղում**: + + .. topic:: Ես ցանկանում եմ նշել բոլոր այն կրկնօրինակները, որոնք պարունակում են "պատճենել" բառը: Ինչպե՞ս դա անել: + + * **Windows**. Սեղմեք **Գործողություններ --> կիրառել ֆիլտրը**, ապա նշեք "պատճենել", հետո սեղմեք ԼԱՎ: + * **Mac OS X**. Նշեք "պատճենել" "Ֆիլտրում" դաշտում՝ գործիքների վահանակում: + * Սեղմեք **Նշել --> Նշել բոլորը**: + +.. only:: edition_me + + .. topic:: Ես ցանկանում եմ հեռացնել բոլոր երգերը, որոնք 3 վայրկյանից հեռու են իրենց հղման ֆայլից: Ի՞նչ կարող եմ ես անել: + + * Միացնել :doc:`Միայն Սխալները ` եղանակում: + * Միացնել **Դելտա նշանակությունները** եղանակը: + * Սեղմեք "Ժամանակը" սյանը՝ դասավորելու համար արդյունքները ըստ ժամանակի: + * Ընտրեք բոլոր կրկնօրինակները՝ -00:03-ից ցածր: + * Սեղմեք **Ջնջել ընտրվածը արդյունքներից**: + * Ընտրել բոլոր կրկնօրինակները 00:03-ից բարձր: + * Սեղմեք **Ջնջել ընտրվածը արդյունքներից**: + + .. topic:: Ես ցանկանում եմ դարձնել իմ բարձրագույն բիթրեյթ ունեցող երգերը հղման ֆայլեր: Ի՞նչ կարող եմ ես անել: + + * Միացնել :doc:`Միայն Սխալները ` եղանակում: + * Միացնել **Դելտա նշանակությունները** եղանակը: + * Սեղմեք "Բիթրեյթը" սյանը՝ դասավորելու համար արդյունքները ըստ բիթրեյթի: + * Սեղմեք "Բիթրեյթը" սյանը՝ կրկնելու համար դասավորման կարգը: + * Ընտրել բոլոր կրկնօրինակները 0-ց բարձր; + * Սեղմեք **Դարձնել ընտրվածը հղում**: + + .. topic:: Ես չեմ ցանկանում [live] և [remix] տարբերակները իմ երգերի՝ հաշված որպես կրկնօրինակ: Ինչպե՞ս դա անել: + + Եթե Ձեր համեմատության սահմանը բավականին ցածր է, հնարավոր է Դուք ավարտվեք կենդանի և ռեմիքս տարբերակներով Ձեր երգերի արդյունեքներում: Դուք ոչինչ չեք կարող անել դրա համար, բայց կա ինչ-որ եղանակ՝ դրանք ստուգման արդյունքներից ջնջելու համար: Եթե օրինակի համար, Դուք ցանկանում եք ջնջել ամեն մի երգ, որը գտնվում է գծիկների միջև []:. + * **Windows**. Սեղմեք **Գործողություններ --> Կիրառել ֆիլտրը**, ապա տեսակը "[*]", ապա սեղմեք ԼԱՎ: + * **Mac OS X**. Տեսակը "[*]" "Ֆիլտր" դաշտում՝ գործիքաշերտի: + * Սեղմեք **Նշել --> Նշել բոլորը**: + * Սեղմեք **Գործողություններ --> Ջնջել ընտրվածը արդյունքներից**. + +.. topic:: Ես փորձում եմ կրկնօրինակները ուղարկել Աղբարկղ, բայց dupeGuru-ն ինձ ասում է, որ չես կարող: Ինչու՞: Ի՞նչ կարող եմ ես անել: + + Շատ ժամանակ, պատճառը, թե ինչու dupeGuru-ն չի կարողանում տեղափոխել ֆայլերը Աղբարկղ, կայանում է ֆայլի լիազորությունների մեջ: Դուք պետք է *գրեք* լիազորությունները ֆայլերում, որոնք որ ցանկանում եք ուղարկել Աղբարկղ: Եթե Ձեզ անծանոթ է Հրամանի տողը, ապա Դուք կարող եք օգտագործել լրացուցիչ գործիքներ, ինչպես օրինակ `BatChmod `_ լիազորումները նշելու համար: + + Եթե dupeGuru-ն դեռ շարունակում է խնդիրներ առաջ բերել կապված լիազորությունների հետ, ապա կան խնդիրներ կապված՝ "Տեղափոխել նշվածը..." որպես շրջանցիկ խորամանկություն: Ուստի ֆայլերը Աղբարկ տեղափոխելիս Դուք ուղարկում եք այն ժամանակավոր թղթապանակ "Տեղափոխել նշվածը..." գործողությամբ և ապա Դուք կջնջեք այդ թղթապանակը ձեռադիր; + + .. only:: edition_pe + + Եթե Դուք փորձում եք ջնջել *iPhoto* նկարները, ապա ձախողման պատճառը տարբեր է: Ջնջելը ձախողվել է, որովհետև dupeGuru-ը չի կարողանում համագործակցել iPhoto: Լինել տեղեկացված, որ ջնջումը նորմալ է աշխատում, Դուք չեք նախատեսում խաղարկել ձայն iPhoto-ին, քանսզի dupeGuru-ն աշխատում է: Նաև, երբեմն, Applescript համակարգը չի կողմնորոշվում որտեղ փնտրել iPhoto՝ բացելու համար: Հավանական է, այս դեպքերում պետք է բացել iPhoto-ն *մինչև* Դուք ուղարկեք Ձեր կրկնօրինակները Աղբարկղ: + + Եթե այս ամենը ձախողվի, `կապնվեք HS աջակցության թիմի հետ `_, մենք կփորձեք օգնել Ձեզ: + +.. todo:: This FAQ qestion is outdated, see english version. \ No newline at end of file diff --git a/help/hy/_sources/folders.rst.txt b/help/hy/_sources/folders.rst.txt new file mode 100644 index 00000000..e09e6f45 --- /dev/null +++ b/help/hy/_sources/folders.rst.txt @@ -0,0 +1,25 @@ +Թղթապանակի ընտրություն +======================= + +Առաջին թղթապանակը, որ Դուք տեսնում եք dupeGuru-ն բացելիս դա թղթապանակի ընտրությունն է: Այս պատուհանը պարունակում է թղթապանակների ցանկը, որոնք կստուգվեն **Ստուգել** սեղմելիս: + +Այս պատուհանը շատ հեշտ է օգտագործել: Եթե ցանկանում եք ավելացնել թղթապանակ, ապա սեղմեք **+** կոճակը: Եթե մինչ այդ ավելացնեք թղթապանակը, ապա կերևա ավելացված վերջին թղթապանակների ցանկը: Կարող եք սեղմել նրանցից մեկի վրա՝ ավելացնելու համար ուղղակի Ձեր ցանկում: Եթե սեղմեք հայտնվող պատուհանի առաջին ֆայլին՝ **Ավելացնել նոր թղթապանակ...**, ապա Ձեզ հարցում կկատարվի թղթապանակ ավելացնելու մասին: Եթե երբեք չեք ավելացրել թղթապանակ, ապա ոչ մի ընտրացանկ չի երևա և Ձեզ ուղղակի հարցում կարվի նոր թղթապանակ ավելացնելու մասին: + +Այլընտրանքյին ճանապարհով թղթապանակներ կարող եք ավելացնել պարզապես դրանք գցելով ցանկում: + +Թղթապանակը հեռացնելու համար ընտրեք թղթապանակը, սեղմեք **-**: Եթե ընտրված է ենթաթղթպանակը, երբ Դուք սեղմում եք կոճակին, ընտրված թղթապանակը կնշվի որպես **բացառված** (նայեք այստեղ)՝ ջնջվելու փոխարեն: + +Թղթապանակի վիճակը +------------------ + +Յուրաքանչյուր թղթապանակ կարող է լինել հետևյալ 3 եղանակներից մեկում. + +* **Նորմալ.** Այս թղթապանակում գտնված կրկնօրինակները կարող են ջնջվել: +* **Հղված.** Կրկնօրինակներ են գտնվել այս թղթապանակում, որոնք **չեն կարող** ջնջվել: Ֆայլերը այս թղթապանակից կարող են միայն ավարտվել **հղում** դիրքով խմբում: Եթե մեկ ֆայլից ավելի են հղման թղթապանակների հղումները, ապա միայն մեկը կպահվի: Մնացածը կջնջվեմ խմբից: +* **Բացառված.** Ֆայլերը այս թղթապանակում կներառվեն ստուգման մեջ: + +Թղթապանակի հիմնական վիճակը, իհարկե՛ **Նորմալ է**: Կարող եք օգտագործել **Հղված** վիճակը թղթապանակի համար, եթե ցանկանում եք համոզված լինել, որ ոչ մի ֆայլ չի ջնջվի: + +Եթե նշել եք թղթապանակի վիճակը, բոլոր ենթաթղթապանակները միանգամից կժառանգեն այս վիճակը, եթե վիճակը պարզորոշ տրված է թղթապանակի կարգում: + +.. todo:: Add iPhoto/Aperture/iTunes libraries notes diff --git a/help/hy/_sources/index.rst.txt b/help/hy/_sources/index.rst.txt new file mode 100644 index 00000000..15c6e920 --- /dev/null +++ b/help/hy/_sources/index.rst.txt @@ -0,0 +1,47 @@ +dupeGuru help +=============== + +.. only:: edition_se + + Այս փաստաթուղթը հասանելի է նաև՝ `Ֆրանսերեն `__ և `Գերմաներեն `__. + +.. only:: edition_me + + Այս փաստաթուղթը հասանելի է նաև՝ `Ֆրանսերեն `__ և `Գերմաներեն `__. + +.. only:: edition_pe + + Այս փաստաթուղթը հասանելի է նաև՝ `Ֆրանսերեն `__ և `Գերմաներեն `__. + +.. only:: edition_se or edition_me + + dupeGuru ծրագիր է՝ գտնելու կրկնօրինակ ունեցող ֆայլեր Ձեր համակարգչում: Այն կարող է անգամ ստուգել ֆայլի անունները կան բովանդակությունը: Ֆայլի անվան ստուգման հնարավորությունները ոչ ճշգրիտ համընկման ալգորիթմով, որը կարող է գտնել ֆայլի անվան կրկնօրինակներ, անգամ եթե դրանք նույնը չեն: + +.. only:: edition_pe + + dupeGuru Picture Edition-ը (PE՝ կարճ) գործիք է, որը գտնում է նկարների կրկնօրինակները Ձեր համակարգչում: Գտնում է ոչ միայն նույնանման կրկնօրինակները, այլ նաև կարող է գտնել տարբեր տեսակի և որակի նկարներ (PNG, JPG, GIF և այլն...): + +Չնայած dupeGuru-ն կարող է հեշտությամբ օգտագործվել առանց օգնության, այնուհանդերձ եթե կարդաք այս ֆայլը, այն մեծապես կօգնի Ձեզ ընկալելու ծրագրի աշխատանքը: Եթե Դուք նայում եք ձեռնարկը կրկնօրինակների առաջին ստուգման համար, ապա կարող եք ընտրել :doc:`Արագ Սկիզբ ` հատվածը: + +Շատ լավ միտք է պահելու dupeGuru թարմացված: Կարող եք բեռնել վեբ կայքի համապատասխան էջից `homepage`_: + +Պարունակությունը. + +.. toctree:: + :maxdepth: 2 + + quick_start + folders + preferences + results + reprioritize + faq + changelog + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` + +.. _homepage: https://www.hardcoded.net/dupeguru \ No newline at end of file diff --git a/help/hy/_sources/preferences.rst.txt b/help/hy/_sources/preferences.rst.txt new file mode 100644 index 00000000..7faeab09 --- /dev/null +++ b/help/hy/_sources/preferences.rst.txt @@ -0,0 +1,63 @@ +Կարգավորումներ +================ + +.. only:: edition_se + + **Ստուգելու տեսակը.** Այս ընտրանքը որոշում է, թե ֆայլերի որ ասպեկտը կհամեմատվի կրկնօրինակված ստուգման հետ: Եթե Դուք ընտրեք **Ֆայլի անունը**, ապա dupeGuru-ն կհամեմատի յուրաքանչյուրը բառ-առ-բառ և կախված է հետևյալ այլ ընտրանքներից, այն կորոշի արդյոք բավական են համընկնող բառերը դիտելու համար 2 ֆայլերի կրկնօրինակները: Եթե ընտրեք միայն **Բովանդակությունը**, ապա նույնատիպ ֆայլերը նույն բովանդակությամբ կհամընկնեն: + + **Թղթապանակներ.** ստուգելու հատուկ տեսակ է: Երբ ընտրեք սա, dupeGuru-ն կստուգի կրկնօրինակ *թղթապանակները*՝ կրկնօրինակ ֆայլերի փոխարեն: Որոշելու համար արդյոք անկախ երկու թղթապանակները կրկնօրինակ են, կստուգվեն թղթապանակների ամբողջ պարունակությունը և եթե **բոլոր** ֆայլերի բովանդակությունը համընկնի, ապա թղթապանակները կորոշվեն որպես կրկնօրինակներ: + + **Ֆիլտրի խստությունը.** Եթե Դուք ընտրեք **Ֆայլի անունը** ստուգելու տեսակը, այս ընտրանքը կորոշի, թե ինչքանով նման պետք է լինեն ֆայլերի անունները, որ dupeGuru-ն ճանաչի դրանք որպես կրկնօրինակներ: Եթե ֆիլտրը առավել խիստ է, օրինակ՝ 80, ապա դա նշանակում է, որ երկու ֆայլերի անունների բառերի 80%-ը պետք է համընկնի: Որոշելու համար համընկնման տոկոսը, dupeGuru-ն նախ հաշվում է բառերի ընդհանուր քիանակը **երկու** ֆայլերի անուններում, ապա հաշվում է համընկնումների քանակը (ամեն բառ համընկնում է 2-ի հաշվին) և բաժանում ընդհանուր գտնված բառերի համընկնումների միջև: Եթե արդյունքը բարձր է կամ հավասար ֆիլտրի խստությանը, ապա մենք ունեք կրկնօրինակի համընկնում: Օրինակ՝ "a b c d" և "c d e" ունեն համընկնման տոկոս, որը հավասար է 57-ի (4 բառ են համընկնում, 7 ընդհանուր բառից): + +.. only:: edition_me + + **Ստուգելու եղանակը.** Այս ընտրանքը որոշում է, թե որ ասպեկտն է ֆայլերի՝ համեմատելի կրկնօրինակման ստուգմանը: Կրկնօրինակների ստուգման բնույթը փոխվում է մեծապես կախված, թե ինչի եք ընտրում այս ընտրանքը: + + * **Ֆայլի անունը.** Ցանկացած երգ ունի իր ֆայլի անվան մասնատումը բառերի և ապա ամեն բառ կհամեմատվի՝ հաշվելու համար համընկնման տոկոսը: Եթե այս տոկոսը ավելի բարձր է կամ հավասար **Ֆիլտրի խստությանը** (նայել՝ մանրամասների համար), dupeGuru-ն կդիտարկի երկու երգերը որպես կրկնօրինակներ: + * **Ֆայլի անունը - Դաշտերը.** Ինչպես օրինակ **Ֆայլի անունը**, բացառում է, որ մեկ ֆայլի անունը բաժանվի բառերի, այս բառերը ապա կխմբավորվեն դաշտերում: Դաշտերի բաժանիչը " - " է: Համընկնման վերջնական տոկոսը կլինի համընկնման ցածրագույն տոկոսը դաշտերի միջև: Այսպիսով, "Կատարողը - Վերնագիրը" և "Կատարողը - Այլ վերնագիրը" կունենա համընկման տոկոս՝ 50 (**Ֆայլի անունը** ստուգմամբ, կլինի 75). + * **Ֆայլի անունը - Դաշտերը (անկարգ).** Ինչպես օրինակ **Ֆայլի անունը - Դաշտերը** բացառությամբ, որ դաշտի կարգը չի համընկնում: Օրինակ՝ "Կատարողը - Վերնագիրը" և "Վերնագիրը - Կատարողը" կունենան համընկնման 100 տոկոս՝ 0-ի փոխարեն: + * **Կցապիտակներ.** Այս եղանակը կարդում է յուրաքանչյուր երգի կցապիտակները (մետատվյալները) և համեմատում է նրանց դաշտերը: Այս եղանակը, ինչպես օրինակ **Ֆայլի անունը - Դաշտերը** դիտարկում են համընկնման ցածրագույն դաշտը՝ համեմատման վերջնական տոկոսից: + * **Պարունակությունը.** Ստուգման այս եղանակը օգտագործում են երգերի բովանդակությունը՝ որոշելու համար, թե որն են կրկնօրինակները: 2 երգերը համընկնեցնելու համար այս եղանակով, դրանք պետք է ունենան **բացառապես նույն բովանդակությունը**: + * **Ձայնի բովանդակությունը.** Նույնն են բովանդակությամբ, բայց միայն ձայնի պարունակությունն է համեմատելի (առանց մետատվյալների): + + **Ֆիլտրի խստությունը.** Եթե ընտրում եք ֆայլի անունը կամ կցապիտակը՝ հիմնված ստուգման եղանակի վրա, ապա այս ընտրանքը որոշում է, թե ինչքան են նման երկու ֆայլի անունները/կցապիտակները պետք է լինեն dupeGuru-ի կողմից դիտարկվող կրկնօրինակներ: Եթե ֆիլտրի խստությունը օրինակի համար 80 է, դա նշանակում է, որ երկու ֆայլի անունների բառերի համընկնումը 80% է: Որոշելու համար համընկնման տոկոսը, dupeGuru-ն առաջին հաշվով որոշում է **երկու** ֆայլի անունների առաջին հաշվարկի ընդհանուր քանակը, ապա համընկնող բառերի համընկնման քանակը (բոլոր բառերը համընկնում են 2-ի) և ապա բաժանել համընկնող բառերի թիվը ընդհանուր բառերի թվին: Եթե արդյունքը բարձր է կամ հավասար ֆիլտրի խստությանը, ապա մենք ունենք կրկնօրինակի համընկնում: Օրինակ՝ "a b c d" և "c d e" ունի համընկնման 57 տոկոս (4 բառերի համընկնում, 7 ընդամենը բառեր): + + **Ստուգվող կցապիտակները.** Երբ օգտագործվում է **Կցապիտակներ** ստուգելու եղանակը, կարող եք ընտրել կցապիտակներ, որոնք կօգտագործվեն համեմատման համար: + +.. only:: edition_se or edition_me + + **Բառի կշիռը.** Եթե ընտրում եք **Ֆայլի անունը** ստուգելու եղանակը, ապա այս ընտրանքը որոշակիորեն փոխում է համընկնման տոկոսը հաշվելու եղանակը: Բառի կշռմամբ կրկնօրինակի քանակի փոխարենը 1 նշանակությունը ունենալու համար, ամեն բառը ունի հավասարազոր նշանակություն՝ առկա գրանշանների թվին: Բառի կշռմամբ, "ab cde fghi" և "ab cde fghij" կունենա համընկնման տոկոս՝ 53% (19 ընդամենը գրանշաններ, 10 գրանշանների համընկնում (4-ը "ab"-ի և 6-ը "cde"-ի համար)): + + **Նմանատիպ բառերի համընկնում.** Եթե միացնեք այս ընտրանքը, նմանատիպ բառերը կհաշվեն որպես համընկնումներ: Օրինակ՝ "Սպիտակ շրջանակ" և "Սպիտակ շրջանակ" ունի համընկնման % հավասարազոր 100-ի՝ 66-ի փոխարեն, եթե ընտրանքը միացված է: **Զգուշացում.** Այս ընտրանքը զգուշությամբ օգտագործեք: Հավանական է ստացված տվյալների մեծ մասը կեղծ լինեն: Այնուհանդերձ, այն կօգնի Ձեզ գտնելու կրկնօրինակներ, որոնք այլ ճանապարհով հնարավոր չի եղել գտնել: Ստուգելու ընթացքը նաև նշանակալի դանդաղ է, եթե այս ընտրանքը միացված է: + +.. only:: edition_pe + + **Ստուգելու եղանակը.** Այս ընտրանքը որոշում է ստուգելու եղանակը, որը կկիրառվի նկարների նկատմամբ: **Պարունակությունը** ստուգելու եղանակը համեմատում է ակտուալ նկարների բովանդակությունը ոչ ճշգրիտ եղանակով (հնարավորություն տալով գտնելու ոչ միայն անմիջապես կրկնօրինակները, այլ նաև նմանատիպ այլ ֆայլերը): **EXIF Timestamp** ստուգելու եղանակը նայում է նկարի EXIF մետատվյալը (եթե այն կա) և համընկնող նկարները, որոնք որ նույնն են: Սա ավելի արագ է, քան բովանդակությամբ ստուգելը: **Զգուշացում.** Փոփոխված նկարները սովորաբար պահում են նույն EXIF timestamp-ը, ուստի նախ նայեք արդյունքները, ապա գործեք: + + **Ֆիլտրի խստությունը.** *Ստուգում է միայն բովանդակությունը:* Այս ընտարնքի բարձրագույն նիշը, բնորոշում է ֆիլտրի "խստությունը" (Այլ կերպ ասաց, արդյունքը ավելի քիչ է լինում): Նույն որակի նկարներից շատերը երբեմն համընկնում են 100%-ով՝ անգամ եթե տեսակը ուրիշ է (PNG և JPG օրինակի համար): Այնուհանդերձ, եթե ցանկանում եք, որ PNG-ն համապատասխանի ցածր որակի JPG-ին, պետք է նշեք ֆիլտրի խստությունը 100-ից ցածր: Ծրագրայինը 95 է: + + **Տարբեր չափերով նկարների համապատասխանեցում.** Եթե ընտրեք սա, տարբեր չափերի նկարները կթույլատրվեն կրկնօրինակվող նույն խմբում: + +**Կարող է ուղղել ֆայլի տեսակը.** Եթե ընտրում եք այս վանդակը, ապա կրկնօրինակվող խմբերը կթույլատրվեն ունենալու տարբեր ընդլայնումներ: Եթե չընտրեք, ապա դրանք չեն լինի! + +**Անտեսել կրկնօրինակների հղումը նույն ֆայլին file:** Եթե այս ընտրանքը միացված է, dupeGuru-ն կստուգի կրկնօրինակները՝ տեսնելու համար արդյոք դրանք հղվում են նույնին `inode `_: Եթե այո, ապա դրանք չեն որոշվի որպես կրկնօրինակ: (Միայն OS X և Linux-ում) + +**Ֆիլտրելիս օգտագործել կանոնավոր սահմանումներ.** Եթե ընտրեք սա, ապա ֆիլտրման հնարավորությունը կդիմի ֆիլտրման հերթին, ինչպես որ **կանոնավոր սահմանում**: Դրա բացատրությունը դուրս կգա այս փաստաթղթի շրջանակից: Ավելին կարող եք կարդալ այստեղ՝ `regular-expressions.info `_: + +**Ջնջել դատարկ թղթապանակները ջնջելուց կամ տեղափոխելուց.** Երբ այս ընտրանքը միացված է, թղթապանակները կջնջվեն, երբ որ ֆայլը ջնջվի կամ տեղափոխվի և թղթապանակը դատարկ լինի: + +**Պատճենել և տեղափոխել.** Որոշում է, թե Պատճենելու և Տեղափոխելու գործողությունները (գործողություն ընտրացանկից): + +* **Տեղադրությունից աջ.** Բոլոր ֆայլերը կուղարկվեն ընտրված տեղ՝ առանց փորձելու վերստեղծելու աղբյուրի ճանապարհը բոլորի համար: +* **Վերստեղծել հարաբերական ճանապարհը.** Աղբյուր ֆայլի ճանապարհը կվերստեղծվի նշանակված թղթապանակում՝ խորքայինից մեկ աստիճան վեր՝ Թղթապանակներ վահանակից: Օրինակ՝ եթե ավելացնեք``/Users/foobar/SomeFolder`` Թղթապանակներ վահանակ և տեղափոխեք ``/Users/foobar/SomeFolder/SubFolder/SomeFile.ext`` նշանակության թղթապանակ ``/Users/foobar/MyDestination``, ֆայլի վերջնական տեղավորությունը կլինի ``/Users/foobar/MyDestination/SubFolder`` (``SomeFolder`` բաժանվել է աղբյուր ճանապարհից վերջնական տեղադրությունում): +* **Վերստեղծել հարաբերական ճանապարհը.** Աղբյուր ֆայլի ճանապարհը կվերստեղծվի նշանակված թղթապանակում՝ իր հարթությունում: Օրինակ՝ եթե տեղափոխեք ``/Users/foobar/SomeFolder/SubFolder/SomeFile.ext`` նշանակության թղթապանակ ``/Users/foobar/MyDestination``, ֆայլի վերջնական տեղավորությունը կլինի ``/Users/foobar/MyDestination/Users/foobar/SomeFolder/SubFolder``: + +Ամեն դեպքում, dupeGuru լավ է հարթում անունների կոնֆլիկտը՝ նախապատրաստելով նշանակության ֆայլի անվան թիվը՝ եթե ֆայլը արդեն առկա է նշված տեղում: + +**Ընտրված հրամանը.** Այս կարգավորումը որոշում է հրամանը, որը կկանչվի "Կանչել Ընտրված հրամանը" գործողությամբ: Կարող եք կանչել ցանկացած արտաքին ծրագիր՝ այս գործողությամբ: Սա կարող է օգտակար լինել եթե օրինակ փոխարենը ունեք տվյալների փոխանցման լավ ծրագիր: + +Հրամանի տեսակը նույնն է, ինչ Դուք կգրեք Հրամանի տողում, բացառությամբ որտեղ կան 2 լրացումներ. **%d** և **%r**: Այս լրացումները կվերագրվեն ընտրված զոհի (%d) ճանապարհով և ընտրված զոհի հղման ֆայլով (%r): + +Եթե կատարելի ֆայլի ճանապարհը պարունակում է բացատներ, ապա պետք է փակեք այն "" չակերտներով: Նաև պետք է փակեք լրացումները չակերտներով, որովհետև շատ հնարավոր է, որ զոհի ճանապարհները և հղումները կպարունակեն բացատներ: Ահա ընտրված հրամանի օրինակ՝ :: + + "C:\Program Files\SuperDiffProg\SuperDiffProg.exe" "%d" "%r" diff --git a/help/hy/_sources/quick_start.rst.txt b/help/hy/_sources/quick_start.rst.txt new file mode 100644 index 00000000..6dc7d2b4 --- /dev/null +++ b/help/hy/_sources/quick_start.rst.txt @@ -0,0 +1,15 @@ +Արագ Սկիզբ +=========== + +Արագ սկսելու համար dupeGuru-ն, պարզապես կատարեք ստանդարտ ստուգում՝ օգտագործելով ծրագրային կարգավորումները: + +* Բացել dupeGuru-ն: +* Ավելացնել թղթապանակներ՝ ստուգելու համար նաև վերցնել & գցելը կամ "+" կոճակը: +* Սեղմեք **Ստուգել**: +* Սպասեք, մինչ ստուգումը կավարտվի: +* Նայեք ցանկացած կրկնօրինակին (Ֆայլեր, որոնք նշվել են) և ստուգվել, իրականում կրկնօրինակել խմբի հղմանը (Ֆայլը կրկնօրինակելուց առաջ չի նշվում և ընտրված չէ): +* Եթե ֆայլը սխալ կրկնօրինակ է, ապա ընտրեք այն և սեղմեք **Գործողություններ-->Հեռացնել ընտրվածը Արդյունքներից**: +* Եթե համոզված եք, որ կրկնօրինակը արդյունքներում կա, ապա սեղմեք **Խմբագրել-->Նշել բոլորը**, և ապա **Գործողություններ-->Ուղարկել Նշվածը Աղբարկղ**: + +Սա միայն բազային ստուգում է: Կան բազմաթիվ կարգավորումներ, որոնք հնարավորություն են տալիս նշելու տարբեր արդյունքներ և մի քանի եղանակներ արդյունքների փոփոխման: Մանրամասների համար կարդացեք Օգնության ֆայլը: + diff --git a/help/hy/_sources/reprioritize.rst.txt b/help/hy/_sources/reprioritize.rst.txt new file mode 100644 index 00000000..2b60a905 --- /dev/null +++ b/help/hy/_sources/reprioritize.rst.txt @@ -0,0 +1,26 @@ +Վերաառաջնայնության կրկնօրինակներ +================================ + +dupeGuru-ը փորձում է որոշել, թե որ կրկնօրինակները պետք է գնան յուրաքանչյուր խմբի դիրքում, +բայց երբեմն սխալ է ստանում: Շատ դեպքերում, խելամիտ դասավորումը "Դելտա նշանակության" +և "Միայն սխալները" ընտրանքների ավելացնելով "Դարձնել ընտրվածը հղում" գործողության խորամանկություն է, բայց +երբեմն, պահանջվում են ավելի լավ ընտրանքներ: Ահա այստեղ է, որ վերաառաջնայնավորման պատուհանը բացվում է: +Կարող եք կանչել այն "Վերաառաջնայնավորման արդյունքները" կետից՝ "Գործողություններ" ընտրացանկից: + +Այս պատուհանը հնարավորություն է տալիս Ձեզ ընտրելու չափանիշներ՝ հղման սխալին համապատասխան և կընտրվի +յուրաքանչյուր սխալի խումբը: Հասանելի չափանիշների ցանկը ձախում է և Ձեր ընտրած չափանիշների ցանկը գտնվում է +աջում: + +Չափանիշն դա բաժինն է, որը հետևում է փաստարկին: Օրինակ՝ "Չափը (Բարձրագույն)" նշանակում է, որ սխալը +հետևում է մեծագույն չափի հաղթողին: "Թղթապանակը (/foo/bar)" նշանակում է, որ սխալները թղթապանակում կհաղթեն: Ավելացնելու համար +փաստարկ ամենաաջ մասում, նախ ընտրեք բաժինը, ապա ընտրեք +ենթափաստարկ հետևյալ ցանկում և ապա սեղմեք կոճակի սլաքի աջ մասում: + +Ցանկի կարգը աջից շատ կարևոր է (կարող եք վերակարգավորել ֆայլերը վերցնել և գցելու միջոցով): Երբ +սխալի տեղորոշումը հղման դիրքում է, ապա օգտագործվում է առաջին փաստարկը: Եթե դա կապված է, ապա երկրորդ +փաստարկն է օգտագործվում և այլն և այլն: Օրինակ, եթե Ձեր փաստարկները "Չափը (բարձրագույն)" են և ապա +"Ֆայլի անունը (Չի ավարտվում թվով)", ապա հղման ֆայլը, որը կընտրվի խմբում, ապա կլինի +մեծագույն ֆայլը և եթե երկու կամ ավելի ֆայլեր ունեն նույն չափը, ապա մեկը ունի ֆայլի անուն, որը +չի ավարտվում թվով, կօգտագործվի: Երբ փաստարկի արդյունքը կապված է, կարգը, որի սխալները +նախկինում էին, խումբը պետք է օգտագործվի: + diff --git a/help/hy/_sources/results.rst.txt b/help/hy/_sources/results.rst.txt new file mode 100644 index 00000000..fb5ab88c --- /dev/null +++ b/help/hy/_sources/results.rst.txt @@ -0,0 +1,101 @@ +Արդյունքները +============= + +Երբ dupeGuru-ն ավարտի կրկնօրինակների ստուգումը, կցուցադրի արդյունքները կրկնօրինակ խմբերի ցանկում: + +Կրկնօրինակ խմբերի մասին +------------------------- + +Կրկնօրինակման խումբը դա ֆայլերի խումբ է, որոնք բոլորը համընկնում են միմյանց: Ամեն խումբ ունի իր **հղվող ֆայլը** և մեկ կամ մի քանի **կրկնօրինակ ֆայլեր**: Հղվող ֆայլը դա խմբի առաջին ֆայլն է: Այն ընտրված չէ, նրանից ցածր և փոխարեն կրկնօրինակ ֆայլերի: + +Կարող եք նշել կրկնօրինակ ֆայլերը, բայց երբեք չեք կարող նշել հղվող ֆայլը խմբում: Սա երկրորդ պատճառն է՝ կանխելու dupeGuru-ին ջնջելու ոչ միայն կրկնօրինակ ֆայլերը, այլև դրանց հղումները: Համոզվա՞ծ եք, չէ, որ պետք չէ անել դա: + +Ինչն է որոշում, թե որ ֆայլերը հղմամբ են և որ ֆայլերը կրկնօրինակ են՝ թղթապանակի նախնական վիճակում: Ֆայլը հղվող թղթապանակից միշտ հղվում է կրկնօրինակի խմբում: Եթե բոլոր ֆայլերը նորմալ թղթապանակից են, ապա չափն է որոշում, թե որ ֆայլը կլինի կրկնօրինակ խմբի հղումը: dupeGuru-ն ընդունում է, որ Դուք կցանկանաք պահել մեծ ֆայլերը, ուստի դրանք կտեղադրվեն հղման խմբում: + +Կարող եք փոխել հղման ֆայլը խմբում ձեռադիր: Դա անելու համար ընտրեք կրկնօրինակ ֆայլը և սեղմեք **Գործողություններ-->Դարձնել ընտրվածը հղմամբ**: + +Նայել արդյունքները +-------------------- + +Չնայած պարզապես կարող եք սեղմել **Խմբագրել-->Նշել բոլորը** և ապա **Գործողություններ-->Ուղարկել նշվածը Աղբարկղ** արագորեն ջնջելու համար բոլոր կրկնօրինակ ֆայլերը արդյունքներից, միշտ խորհուրդ է տրվում նախ նայել կրկնօրինակները և հետո միայն ջնջել: + +Օգնելու համար Ձեզ նայելու արդյունքները, կարող եք օգտագործել **Մանրամասների վահանակը**: Այս վահանակը ցուցադրում է բոլոր մանրամասները ընտրված ընթացիկ ֆայլի, ինչպես նաև հղման մանրամասները: Սա շատ հարմար է արագորեն որոշելու, թե արդյոք կրկնօրինակը իրոքից կրկնօրինակ է, թե ոչ: Կարող եք նաև կրկնակի սեղմեք ֆայլի վրա՝ բացելու համար այն նրա հետ ասոցիացված ծրագրով: + +Եթե ունեք շատ սխալ կրկնօրինակներ, ապա ճիշտ կրկնօրինակները (Եթե Ձեր ֆիլտրի խստությունը շատ է ցածր) որոշելու լավագույն եղանակը դրանք նայելն է, ընտրեք ճիշտ կրկնօրինակները և ապա սեղմեք **Գործողություններ-->Ուղարկել նշվածները Աղբարկղ**: Եթե իսկական կրկնօրինակները ավելի շատ են, քան սխալները, ապա կարող եք օգտագործել **Գործողություններ-->Ջնջել նշվածները արդյունքներից**: + +Նշում և Ընտրում +--------------------- + +**նշվածը** կրկնօրինակ է՝ նշված նշանով, որը ընտրվում է: **ընտրվածը** կրկնօրինակ է, որը ընդգծվում է կամ առանձնացվում է: Ընտրելու բազմակի եղանակները կարող են կատարվել dupeGuru-ում ստանդարտ ճանապարհով (Shift/Command/Control սեղմամբ): կարող եք փոփոխել բոլոր ընտրված կրկնօրինակների վիճակը՝ սեղմելով **space**: + +Ցուցադրել Միայն Սխալները +------------------------- + +Եթե այս ընտրանքը միացված է, ապա կրկնօրինակները ցուցադրվում են առանց իրենց համապատասխան հղվող ֆայլի։ Կարող եք ընտրել, նծել կամ դասավորել այս ցանկը, ինչպես օոր նորմալ եղանակում։ + +dupeGuru-ի արդյունքները, երբ այն նորմալ եղանակում է, դասավորվում են համաձայն կրկնօրինակվող խմբերի' **հղվող ֆայլի** ։ Սա նշանակում է, որ եթե Դուք ցանկանաք, օրինակի համար, նշել բոլոր կրկնօրինակները "exe" ընդլայնմամբ, ապա չեք կարող պարզապես դասավորել արդյունքները ըստ "Տեսակի"՝ ունենալու համար բոլոր exe կրկնօրինակները միասին, որովհետև խումբը կարող է կազմված լինի մեկից ավելի ֆայլերից։ Ահա այստեղ է, որ աշխատում է Միայն Սխալները եղանակը։ Նշելու համար բոլոր "exe" կրկնօրինակները, Դուք պարզապես պետք է՝ + +* Միացնեք Միայն Սխալները եղանակը։ +* Ավելացնեք "Տեսակը" սյունը՝ "Սյուներ" ընտրացանկին։ +* Սեղմեք "Տեսակը" սյանը՝ դասավորելու համար ցանկը ըստ տեսակի։ +* Տեղադրել "exe" տեսակի առաջին կրկնօրինակը։ +* Ընտրեք այն։ +* Պտտեք ներքև ցանկում՝ տեղադրելու համար "exe" տեսակի վերջին կրկնօրինակը։ +* Սեղմած պահեք Shift-ը և սեղմեք նրա վրա։ +* Սեղմեք Space՝ նշելու համար բոլոր կրկնօրինակները։ + +Դելտա նշանակությունները +-------------------------- + +Եթե միացնեք սա, որոշ սյուներ կցուցադրվեն նշանակություն՝ հարաբերական կրկնօրինակների հղմանը՝ բացարձակ նշանակությունների փոխարեն։ Այս դելտա նշանակությունները նաև կցուցադրվեն տարբեր գույներով, ուստի կարող եք դրանք հեշտությամբ տեսնել։ Օրինակ՝ եթե կրկնօրինակը 1.2 ՄԲ է և եթե նրա հղումը 1.4 ՄԲ է, ապա Չափը սյունում կցուցադրվի -0.2 ՄԲ։ + +Միայն Սխալները և Դելտա նշանակությունները +------------------------------------------ + +Միայն Սխալները եղանակը բացում է իր իսկական ուժը, երբ Դուք օգտագործում եք այն Դելտա նշանակությունների հետ։ Երբ միացնեք այն, բացարձակ նշանակությունների փոխարեն կցուցադրվեն հարաբերական նշանակությունները։ Այսպիսով օրինակ, եթե ցանկանում եք արդյունքներից հեռացնել բոլոր կրկնօրինակները, որոնք 300 Կբ-ից մեծ են իրենց հղումներից, ապա չեք կարող դասավորել միայն սխալները արդյունքները ըստ չափի, այդ դեպքում ընտրեք բոլոր կրկնօրինակները, որոնք -300 են Չափը սյունից, ջնջեք դրանք և ապա արեք նույն գործողությունը նաև 300-ից բարձր կրկնօրինակների համար՝ ցանկի ներքևում։ + +Կարող եք նաև օգտագործել սա՝ փոխելու համար կրկնօրինակման ցանկի հղման առաջնայնությունը։ Նոր ստուգումը կատարելուց հետո, եթե չլինեն հղվող թղթապանակներ, հղվող ֆայլը ամեն խմբի կլինի ամենամեծ ֆայլը։ Եթե ցանկանում եք փոխել այն, օրինակի համար, ըստ վերջին փոփոխման ժամանակի, կարող եք դասավորել միայն սխալները արդյունքները ըստ փոփոխման ժամանակի **նվազման** կարգով, ընտրեք բոլոր կրկնօրինակները, որոնց փոփոխման դելտա ժամանակը բարձր է 0-ից և սեղմեք **Դարձնել ընտրվածը հղում**։ Պատճառը,որ դասավորում եք ըստ նվազման կարգի այն է, որ եթե 2 ֆայլերից, որոնք կընտրվեն նույն կրկնօրինակ խմբում, երբ սեղմեք **Դարձնել ընտրվածը հղում**, ապա ցանկի միայն առաջինը կդառնա հղում, մյուսները կանտեսվեն։ Եվ մինչև Դուք ցանկանաք վերջին փոփոխված ֆայլը դարձնել փոփոխված՝ ունենալով դասավորման նվազման կարգը, ապա ցանկի առաջին ֆայլը կլինի վերջին փոփոխված ֆայլը։ + +.. todo:: Add "Non-numerical delta" information. + +Ֆիլտրում +--------- + +dupeGuru-ն աջակցում է հետստուգման ֆիլտրում։ Սրանով Դուք կարող եք սեղմել ներքև արդյունքները, որպեսզի կարողանաք կատարեք գործողություններ դրա հետ։ Օրինակ՝ կարող եք հեշտությամբ նշել բոլոր կրկնօրինակերը նրանց անվան մեջ պարունակող "պատճեն" հատկությամբ՝ ֆիլտրի կողմից օգտագործված արդյունքներից։ + +.. todo:: Qt has a toolbar search field now, not a menu item. + +**Windows.** Ֆիլտրելու հնարավորությունը օգտագործելու համար սեղմեք Գործողություններ --> Կիրառել ֆիլտրը, գրեք կիրառվող ֆիլտրը և սեղմեք Կիրառել։ Չֆիլտրված արդյունքներին վերադառնալու համար սեղմեք Գործողություններ --> Չեղարկել ֆիլտրը։ + +**Mac OS X.** Ֆիլտրելու հնարավորությունը օգտագործելու համար նշեք Ձեր ֆիլտրը "Ֆիլտր" որոնման դաշտում գործիքաշերտի։ Չֆիլտրված արդյունքներին վերադառնալու համար սեղմեք դատարկ թողեք դաշտը կամ սեղմեք "X"։ + +Պարզ եղանակում (ծրագրային եղանակն է), ինչ տեսակի ֆիլտր է տողում օգտագործվել փաստացի ֆիլտրման համար, խմբային նիշի բացառությամբ **\***. Այսպիսով, եթե նշում եք "[*]" որպես ֆիլտր, այն կհամընկնի [] փակագծերի հետ, այնուհանդերձ կլինի այդ փակագծերի միջև։ + +Լրացուցիչ ընդլայնված ֆիլտրման համար, կարող եք միացնել "Ֆիլտրելիս օգտագործել կանոնավոր սահմանումները"։ Ապա ֆիլտրման հնարավորությունը կօգտագործվի **կանոնավոր սահմանմամբ** ։ Կանոնավոր սահմանումը դա համապատասխանացման տեքստի լեզուն է։ Առավել մանրամասն կարող եք կարդալ `regular-expressions.info `_ կայքում։ + +Համապատասխանեցումները զգայուն չեն ո՛չ պարզ, ո՛չ էլ regexp եղանակում։ + +Համապատասխանեցման ֆիլտրի դեպքում, Ձեր կանոնավոր սահմանումը չի ունենա ամբողջական ֆայլի անունը, այն միայն կպարունակի սահմանմանը համապատասխան տողին։ + +Կարող եք տեղեկացնել, որ ոչ բոլոր կրկնօրինակներն են ֆիլտրված արդյունքներում համապատասխանում ֆիլտրին։ Ահա թե ինչու ինչքան շուտ որ պարզ կրկնօրինակը խմբում համապատասխանի ֆիլտրին ամբողջ խումբը կմնա արդյունքներում, ուստի ավելի հեշտ կլինի նայելու կրկնօրինակների կազմը։ Այնուհանդերձ, չհամապատասխանող կրկնօրինակերը "հղման եղանակում են"։ Չնայած որ Դուք կարող եք կատարել գործողություններ, ինչպես օրինակ նշել բոլորը և համոզված լինեք, որ միայն նշված են ֆիլտրված կրկնօրինակերը։ + +Գործողություններ Ընտրացանկը +---------------------------- + +* **Մաքրել անտեսման ցանկը.** Հեռացնում է Ձեր ավելացրած բոլոր անտեսված համընկնումները։ Դուք պետք է սկսեք նոր ստուգում, որպեսզի նոր մաքրված անտեսումների ցանկը էֆֆեկտիվ լինի։ +* **Արտածել արդյունքները XHTML-ով.** Վերցնում է ընթացիկ արդյունքները և ստեղծում XHTML ֆայլը։ Սյուննրը, որոնք տեսանելի են այս կոճակը սեղմելիս կլինեն նաև XHTML ֆայլում։ Ֆայլը միանգամից կբացվի հիմնական դիտարկիչում։ +* **Ուղարկել նշվածները Աղբարկղ.** Բոլոր նշված կրկնօրինակերը հեռացնում է Աղբարկղ։ +* **Ջնջել նշվածը և Վերագրել հղմամբ.** Բոլոր նշված կրկնօրինակերը հեռացնում է Աղբարկղ, բայց դա անելուց հետո ջնջված ֆայլերը վերագրվում են ըստ `հղման `_ հղվող ֆայլում (Միայն OS X և Linux-ում) +* **Տեղափոխել նշվածը՝...:** Հարցնում է Ձեզ թղթապանակի մասին և ապա տեղափոխում է բոլոր նշված ֆայլերը այդ թղթապանակ։ Աղբյուր ֆայլերի ճանապարհը կարող է վերստեղծվել նշանակության թղթապանակում՝ կախված "Պատճենելու և Տեղափոխելու" կարգավորումներից։ +* **Պատճենել նշվածը՝...:** Հարցնում է Ձեզ թղթապանակի մասին և ապա պատճենում է բոլոր նշված ֆայլերը այդ թղթապանակ։ Աղբյուր ֆայլերի ճանապարհը կարող է վերստեղծվել նշանակության թղթապանակում՝ կախված "Պատճենելու և Տեղափոխելու" կարգավորումներից։ +* **Հեռացնել նշվածները արդյունքներից.** Հեռացնում է բոլոր նշված կրկնօրինակները արդյունքներից։ Ակտուալ ֆայլերին դա չի վերաբերվի և դրանք կմնան։ +* **Հեռացնել ընտրվածները արդյունքներից.** Հեռացնում է բոլոր ընտրված կրկնօրինակները արդյունքներից։ Հիշեք, որ ընտրված բոլոր հղվող ֆայլերը կանտեսվեն,այս գործողությամբ կջնջվեն միայն կրկնօրինակերը։ +* **Դարձնել ընտրվածը հղում.** Առաջ է մղում բոլոր ընտրված կրկնօրինակները որպես հղումներ։ Եթե կրկնօրինակը խմբի մասն է, որը ունի հղման թղթապանակ (կապույտ գույնով), ապա ոչ մի գործողություն չի կատարվի դրա համար։ Իսկ եթե միևնույն խմբում կան մեկից ավելի ընտրված կրկնօրինակներ, ապա առաջ կմղվի ամեն խմբից միայն առաջինը։ +* **Ավելացնել ընտրվածը անտեսումների ցանկին.** Նախ բոլոր կրկնօրինակները հեռացվում են արդյունքների ցանկից, ապա ավելացվում է կրկնօրինակի համընկումը և ընթացիկ հղումը անտեսումների ցանկին։ Այս համընկնումը այլևս առաջ չի գա հետագա ստուգումների ժամանակ։ Կրկնօրինակը կարող է հետ բերվել, բայց այն կհամապատասխանի հղման այլ ֆայլի։ Կարող եք մաքրել անտեսումների ցանկը Մաքրել անտեսումների ցանկը հրամանով։ +* **Բացել ընտրվածը հիմական ծրագրով.** Բացում է ֆայլը իր հետ ասոցիացված ծրագրով։ +* **Ցուցադրել ընտրվածը որոնման մեջ.** Բացում է ֆայլը պարունակող թղթապանակը։ +* **Կանչել Ընտրված հրամանը.** Բացում է կարգավորումներոմ Ձեր կողմից նշված արտաքին ծրագիրը։ +* **Անվանափոխել ընտրվածը.** Ձեզ հարցում կկատարվի նոր անվան համար, ապա ընտրված ֆայլը կանվանափոխվի։ + +.. todo:: Add Move and iPhoto/iTunes warning +.. todo:: Add "Deletion Options" section. \ No newline at end of file diff --git a/help/hy/_static/ajax-loader.gif b/help/hy/_static/ajax-loader.gif new file mode 100644 index 00000000..61faf8ca Binary files /dev/null and b/help/hy/_static/ajax-loader.gif differ diff --git a/help/hy/_static/alert_info_32.png b/help/hy/_static/alert_info_32.png new file mode 100644 index 00000000..ea4d1baf Binary files /dev/null and b/help/hy/_static/alert_info_32.png differ diff --git a/help/hy/_static/alert_warning_32.png b/help/hy/_static/alert_warning_32.png new file mode 100644 index 00000000..a687c3dc Binary files /dev/null and b/help/hy/_static/alert_warning_32.png differ diff --git a/help/hy/_static/basic.css b/help/hy/_static/basic.css new file mode 100644 index 00000000..c7adab45 --- /dev/null +++ b/help/hy/_static/basic.css @@ -0,0 +1,665 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 59em; + max-width: 70em; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/help/hy/_static/bg-page.png b/help/hy/_static/bg-page.png new file mode 100644 index 00000000..fe0a6dc8 Binary files /dev/null and b/help/hy/_static/bg-page.png differ diff --git a/help/hy/_static/bullet_orange.png b/help/hy/_static/bullet_orange.png new file mode 100644 index 00000000..1cb8097c Binary files /dev/null and b/help/hy/_static/bullet_orange.png differ diff --git a/help/hy/_static/comment-bright.png b/help/hy/_static/comment-bright.png new file mode 100644 index 00000000..15e27edb Binary files /dev/null and b/help/hy/_static/comment-bright.png differ diff --git a/help/hy/_static/comment-close.png b/help/hy/_static/comment-close.png new file mode 100644 index 00000000..4d91bcf5 Binary files /dev/null and b/help/hy/_static/comment-close.png differ diff --git a/help/hy/_static/comment.png b/help/hy/_static/comment.png new file mode 100644 index 00000000..dfbc0cbd Binary files /dev/null and b/help/hy/_static/comment.png differ diff --git a/help/hy/_static/doctools.js b/help/hy/_static/doctools.js new file mode 100644 index 00000000..0c15c009 --- /dev/null +++ b/help/hy/_static/doctools.js @@ -0,0 +1,311 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var bbox = span.getBBox(); + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + var parentOfText = node.parentNode.parentNode; + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); \ No newline at end of file diff --git a/help/hy/_static/documentation_options.js b/help/hy/_static/documentation_options.js new file mode 100644 index 00000000..84479c76 --- /dev/null +++ b/help/hy/_static/documentation_options.js @@ -0,0 +1,9 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: '', + VERSION: '4.0.3', + LANGUAGE: 'hy', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' +}; \ No newline at end of file diff --git a/help/hy/_static/down-pressed.png b/help/hy/_static/down-pressed.png new file mode 100644 index 00000000..5756c8ca Binary files /dev/null and b/help/hy/_static/down-pressed.png differ diff --git a/help/hy/_static/down.png b/help/hy/_static/down.png new file mode 100644 index 00000000..1b3bdad2 Binary files /dev/null and b/help/hy/_static/down.png differ diff --git a/help/hy/_static/file.png b/help/hy/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/help/hy/_static/file.png differ diff --git a/help/hy/_static/haiku.css b/help/hy/_static/haiku.css new file mode 100644 index 00000000..75af2a5c --- /dev/null +++ b/help/hy/_static/haiku.css @@ -0,0 +1,376 @@ +/* + * haiku.css_t + * ~~~~~~~~~~~ + * + * Sphinx stylesheet -- haiku theme. + * + * Adapted from http://haiku-os.org/docs/Haiku-doc.css. + * Original copyright message: + * + * Copyright 2008-2009, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Francois Revol + * Stephan Assmus + * Braden Ewing + * Humdinger + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +html { + margin: 0px; + padding: 0px; + background: #FFF url(bg-page.png) top left repeat-x; +} + +body { + line-height: 1.5; + margin: auto; + padding: 0px; + font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; + min-width: 59em; + max-width: 70em; + color: #333333; +} + +div.footer { + padding: 8px; + font-size: 11px; + text-align: center; + letter-spacing: 0.5px; +} + +/* link colors and text decoration */ + +a:link { + font-weight: bold; + text-decoration: none; + color: #dc3c01; +} + +a:visited { + font-weight: bold; + text-decoration: none; + color: #892601; +} + +a:hover, a:active { + text-decoration: underline; + color: #ff4500; +} + +/* Some headers act as anchors, don't give them a hover effect */ + +h1 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h2 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h3 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h4 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +a.headerlink { + color: #a7ce38; + padding-left: 5px; +} + +a.headerlink:hover { + color: #a7ce38; +} + +/* basic text elements */ + +div.content { + margin-top: 20px; + margin-left: 40px; + margin-right: 40px; + margin-bottom: 50px; + font-size: 0.9em; +} + +/* heading and navigation */ + +div.header { + position: relative; + left: 0px; + top: 0px; + height: 85px; + /* background: #eeeeee; */ + padding: 0 40px; +} +div.header h1 { + font-size: 1.6em; + font-weight: normal; + letter-spacing: 1px; + color: #0c3762; + border: 0; + margin: 0; + padding-top: 15px; +} +div.header h1 a { + font-weight: normal; + color: #0c3762; +} +div.header h2 { + font-size: 1.3em; + font-weight: normal; + letter-spacing: 1px; + text-transform: uppercase; + color: #aaa; + border: 0; + margin-top: -3px; + padding: 0; +} + +div.header img.rightlogo { + float: right; +} + + +div.title { + font-size: 1.3em; + font-weight: bold; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-bottom: 25px; +} +div.topnav { + /* background: #e0e0e0; */ +} +div.topnav p { + margin-top: 0; + margin-left: 40px; + margin-right: 40px; + margin-bottom: 0px; + text-align: right; + font-size: 0.8em; +} +div.bottomnav { + background: #eeeeee; +} +div.bottomnav p { + margin-right: 40px; + text-align: right; + font-size: 0.8em; +} + +a.uplink { + font-weight: normal; +} + + +/* contents box */ + +table.index { + margin: 0px 0px 30px 30px; + padding: 1px; + border-width: 1px; + border-style: dotted; + border-color: #e0e0e0; +} +table.index tr.heading { + background-color: #e0e0e0; + text-align: center; + font-weight: bold; + font-size: 1.1em; +} +table.index tr.index { + background-color: #eeeeee; +} +table.index td { + padding: 5px 20px; +} + +table.index a:link, table.index a:visited { + font-weight: normal; + text-decoration: none; + color: #dc3c01; +} +table.index a:hover, table.index a:active { + text-decoration: underline; + color: #ff4500; +} + + +/* Haiku User Guide styles and layout */ + +/* Rounded corner boxes */ +/* Common declarations */ +div.admonition { + -webkit-border-radius: 10px; + -khtml-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; + border-style: dotted; + border-width: thin; + border-color: #dcdcdc; + padding: 10px 15px 10px 15px; + margin-bottom: 15px; + margin-top: 15px; +} +div.note { + padding: 10px 15px 10px 80px; + background: #e4ffde url(alert_info_32.png) 15px 15px no-repeat; + min-height: 42px; +} +div.warning { + padding: 10px 15px 10px 80px; + background: #fffbc6 url(alert_warning_32.png) 15px 15px no-repeat; + min-height: 42px; +} +div.seealso { + background: #e4ffde; +} + +/* More layout and styles */ +h1 { + font-size: 1.3em; + font-weight: bold; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-top: 30px; +} + +h2 { + font-size: 1.2em; + font-weight: normal; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-top: 30px; +} + +h3 { + font-size: 1.1em; + font-weight: normal; + color: #0c3762; + margin-top: 30px; +} + +h4 { + font-size: 1.0em; + font-weight: normal; + color: #0c3762; + margin-top: 30px; +} + +p { + text-align: justify; +} + +p.last { + margin-bottom: 0; +} + +ol { + padding-left: 20px; +} + +ul { + padding-left: 5px; + margin-top: 3px; +} + +li { + line-height: 1.3; +} + +div.content ul > li { + -moz-background-clip:border; + -moz-background-inline-policy:continuous; + -moz-background-origin:padding; + background: transparent url(bullet_orange.png) no-repeat scroll left 0.45em; + list-style-image: none; + list-style-type: none; + padding: 0 0 0 1.666em; + margin-bottom: 3px; +} + +td { + vertical-align: top; +} + +code { + background-color: #e2e2e2; + font-size: 1.0em; + font-family: monospace; +} + +pre { + border-color: #0c3762; + border-style: dotted; + border-width: thin; + margin: 0 0 12px 0; + padding: 0.8em; + background-color: #f0f0f0; +} + +hr { + border-top: 1px solid #ccc; + border-bottom: 0; + border-right: 0; + border-left: 0; + margin-bottom: 10px; + margin-top: 20px; +} + +/* printer only pretty stuff */ +@media print { + .noprint { + display: none; + } + /* for acronyms we want their definitions inlined at print time */ + acronym[title]:after { + font-size: small; + content: " (" attr(title) ")"; + font-style: italic; + } + /* and not have mozilla dotted underline */ + acronym { + border: none; + } + div.topnav, div.bottomnav, div.header, table.index { + display: none; + } + div.content { + margin: 0px; + padding: 0px; + } + html { + background: #FFF; + } +} + +.viewcode-back { + font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; + margin: -1px -10px; + padding: 0 12px; +} + +/* math display */ +div.math p { + text-align: center; +} \ No newline at end of file diff --git a/help/hy/_static/jquery-3.2.1.js b/help/hy/_static/jquery-3.2.1.js new file mode 100644 index 00000000..d2d8ca47 --- /dev/null +++ b/help/hy/_static/jquery-3.2.1.js @@ -0,0 +1,10253 @@ +/*! + * jQuery JavaScript Library v3.2.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2017-03-20T18:59Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.2.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Simple selector that can be filtered directly, removing non-Elements + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + // Complex selector, compare the two sets, removing non-Elements + qualifier = jQuery.filter( qualifier, elements ); + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( jQuery.isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ jQuery.camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( jQuery.camelCase ); + } else { + key = jQuery.camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( ">tbody", elem )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i, + val = 0; + + // If we already have the right measurement, avoid augmentation + if ( extra === ( isBorderBox ? "border" : "content" ) ) { + i = 4; + + // Otherwise initialize for horizontal or vertical properties + } else { + i = name === "width" ? 1 : 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with computed style + var valueIsBorderBox, + styles = getStyles( elem ), + val = curCSS( elem, name, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Fall back to offsetWidth/Height when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + if ( val === "auto" ) { + val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + } + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnothtmlwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, isFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + +
+ + +
+

Changelog

+

About the word "crash": When reading this changelog, you might be alarmed at the number of fixes +for "crashes". Be aware that when the word "crash" is used here, it refers to "soft crashes" which +don't cause the application to quit. You simply get an error window that asks you if you want to +send the crash report to Hardcoded Software. Crashes that cause the application to quit are called +"hard crashes" in this changelog.

+
+

4.0.3 (2016-11-24)

+
    +
  • Add new picture cache backend: shelve
  • +
  • Make shelve picture cache backend the active one on MacOS to fix #394 more +elegantly. [cocoa]
  • +
  • Remove Sparkle (auto-updates) due to technical limitations. [cocoa]
  • +
+
+
+

4.0.2 (2016-10-09)

+
    +
  • Fix systematic crash in Picture Mode under MacOS Sierra. (#394)
  • +
  • No change for Linux. Just keeping version in sync.
  • +
+
+
+

4.0.1 (2016-08-24)

+
    +
  • Add Greek localization, by Gabriel Koutilellis. (#382)
  • +
  • Fix localization base path. [qt] (#378)
  • +
  • Fix broken load results dialog. [qt]
  • +
  • Fix crash on load results. [cocoa] (#380)
  • +
  • Save preferences more predictably. [qt] (#379)
  • +
  • Fix picture mode's fuzzy block scanner threshold. (#387)
  • +
+
+
+

4.0.0 (2016-07-01)

+
    +
  • Merge Standard, Music and Picture editions in the same application!
  • +
  • Improve documentation. (#294)
  • +
  • Add Polish, Korean, Spanish and Dutch localizations.
  • +
  • qt: Fix wrong use_regexp option propagation to core. (#295)
  • +
  • qt: Fix progress window mistakenly showing up on startup. (#357)
  • +
  • Bump Python requirement to v3.4.
  • +
  • Bump OS X requirement to 10.8
  • +
  • Drop Windows support, maybe temporarily. +Details <https://www.hardcoded.net/archive2015`#2015-11-01>`_
  • +
  • cocoa: Drop iPhoto, Aperture and iTunes support. Was unmaintained and obsolete.
  • +
  • Drop "Audio Contents" scan type. Was confusing and seldom useful.
  • +
  • Change license to GPLv3
  • +
+
+
+

3.9.1 (2014-10-17)

+
    +
  • Fixed AttributeError: 'ComboboxModel' object has no attribute 'reset'. [Linux, Windows] (#254)
  • +
  • Fixed PermissionError on saving results. (#266)
  • +
  • Fixed a build problem introduced by Sphinx 1.2.3.
  • +
  • Updated German localisation, by Frank Weber.
  • +
+
+
+

3.9.0 (2014-04-19)

+
    +
  • This is mostly a dependencies upgrade.
  • +
  • Upgraded to Python 3.3.
  • +
  • Upgraded to Qt 5.
  • +
  • Minimum Windows version is now Windows 7 64bit.
  • +
  • Minimum Ubuntu version is now 14.04.
  • +
  • Minimum OS X version is now 10.7 (Lion).
  • +
  • ... But with a couple of little improvements.
  • +
  • Improved documentation.
  • +
  • Overwrite subfolders' state when setting states in folder dialog (#248)
  • +
  • The error report dialog now brings the user to Github issues.
  • +
+
+
+

3.8.0 (2013-12-07)

+
    +
  • Disable symlink/hardlink deletion option when not relevant. (#247)
  • +
  • Make Cmd+A select all folders in the Folder Selection dialog. [Mac] (#228)
  • +
  • Make non-numeric delta comparison case insensitive. (#239)
  • +
  • Fix surrogate-related UnicodeEncodeError on CSV export. (#210)
  • +
  • Fixed crash on Dupe Count sorting with Delta + Dupes Only. (#238)
  • +
  • Improved documentation.
  • +
  • Important internal refactorings.
  • +
  • Dropped Ubuntu 12.04 and 12.10 support.
  • +
  • Removed the fairware dialog (More Info).
  • +
+
+
+

3.7.1 (2013-08-19)

+
    +
  • Fixed folder scan type, which was broken in v3.7.0.
  • +
+
+
+

3.7.0 (2013-08-17)

+
    +
  • Improved delta values to support non-numerical values. (#213)
  • +
  • Improved the Re-Prioritize dialog's UI. (#224)
  • +
  • Added hardlink/symlink support on Windows Vista+. (#220)
  • +
  • Dropped 32bit support on Mac OS X.
  • +
  • Added Vietnamese localization by Phan Anh.
  • +
+
+
+

3.6.1 (2013-04-28)

+
    +
  • Improved "Make Selection Reference" to make it clearer. (#222)
  • +
  • Improved "Open Selected" to allow opening more than one file at once. (#142)
  • +
  • Fixed a few typos here and there. (#216 #225)
  • +
  • Tweaked the fairware dialog (More Info).
  • +
  • Added Arch Linux packaging
  • +
  • Added a 64-bit build for Windows.
  • +
  • Improved Russian localization by Kyrill Detinov.
  • +
  • Improved Brazilian localization by Victor Figueiredo.
  • +
+
+
+

3.6.0 (2012-08-08)

+
    +
  • Added "Export to CSV". (#189)
  • +
  • Added "Replace with symlinks" to complement "Replace with hardlinks". [Mac, Linux] (#194)
  • +
  • dupeGuru now tells how many duplicates were affected after each re-prioritization operation. (#204)
  • +
  • Added Longest/Shortest filename criteria in the re-prioritize dialog. (#198)
  • +
  • Fixed result table cells which mistakenly became writable in v3.5.0. [Mac] (#203)
  • +
  • Fixed "Rename Selected" which was broken since v3.5.0. [Mac] (#202)
  • +
  • Fixed a bug where "Reset to Defaults" in the Columns menu wouldn't refresh menu items' marked state.
  • +
  • Added Brazilian localization by Victor Figueiredo.
  • +
+
+
+

3.5.0 (2012-06-01)

+
    +
  • Added a Deletion Options panel.
  • +
  • Greatly improved memory usage for big scans.
  • +
  • Added a keybinding for the filter field. (#182) [Mac]
  • +
  • Upgraded minimum requirements for Ubuntu to 12.04.
  • +
+
+
+

3.4.1 (2012-04-14)

+
    +
  • Fixed the "Folders" scan type. [Mac]
  • +
  • Fixed localization issues. [Windows, Linux]
  • +
+
+
+

3.4.0 (2012-03-29)

+
    +
  • Improved results window UI. [Windows, Linux]
  • +
  • Added a dialog to edit the Ignore List.
  • +
  • Added the ability to sort results by "marked" status.
  • +
  • Fixed "Open with default application". (#190)
  • +
  • Fixed a bug where there would be a false reporting of discarded matches. (#195)
  • +
  • Fixed various localization glitches.
  • +
  • Fixed hard crashes on crash reporting. (#196)
  • +
  • Fixed bug where the details panel would show up at inconvenient places in the screen. [Windows, Linux]
  • +
+
+
+

3.3.3 (2012-02-01)

+
    +
  • Fixed crash on adding some folders. [Mac OS X]
  • +
  • Added Ukrainian localization by Yuri Petrashko.
  • +
+
+
+

3.3.2 (2012-01-16)

+
    +
  • Fixed random hard crashes (yeah, again). [Mac OS X]
  • +
  • Fixed crash on Export to HTML. [Windows, Linux]
  • +
  • Added Armenian localization by Hrant Ohanyan.
  • +
  • Added Russian localization by Igor Pavlov.
  • +
+
+
+

3.3.1 (2011-12-02)

+
    +
  • Fixed a couple of nasty crashes.
  • +
+
+
+

3.3.0 (2011-11-30)

+
    +
  • Added multiple-selection in folder selection dialog for a more efficient folder removal. (#179)
  • +
  • Fixed a crash in the prioritize dialog. (#178)
  • +
  • Fixed a bug where mass marking with a filter would mark more than filtered duplicates. (#181)
  • +
  • Fixed random hard crashes. [Mac OS X] (#183 #184)
  • +
  • Added Czech localization by Aleš Nehyba.
  • +
  • Added Italian localization by Paolo Rossi.
  • +
+
+
+

3.2.1 (2011-10-02)

+
    +
  • Fixed a couple of broken action bindings from v3.2.0.
  • +
+
+
+

3.2.0 (2011-09-27)

+
    +
  • Added duplicate re-prioritization dialog. (#138)
  • +
  • Added font size preference for duplicate table. (#82)
  • +
  • Added Quicklook support. [Mac OS X] (#21)
  • +
  • Improved behavior of Mark Selected. (#139)
  • +
  • Improved filename sorting. (#169)
  • +
  • Added Chinese (Simplified) localization by Eric Dee.
  • +
  • Tweaked the fairware system.
  • +
  • Upgraded minimum requirements to OS X 10.6 and Ubuntu 11.04.
  • +
+
+
+

3.1.2 (2011-08-25)

+
    +
  • Fixed a bug preventing the Folders scan from working. (#172)
  • +
+
+
+

3.1.1 (2011-08-24)

+
    +
  • Added German localization by Gregor Tätzner.
  • +
  • Improved OS X Lion compatibility. [Mac OS X]
  • +
  • Made the file collection phase cancellable. (#168)
  • +
  • Fixed glitch in folder window upon selecting a folder state. [Windows, Linux] (#165)
  • +
  • Fixed a text coloring glitch in the results. (#156)
  • +
  • Fixed glitch in the sorting feature of the Folder column. (#161)
  • +
  • Make sure that saved results have the ".dupeguru" extension. [Linux] (#157)
  • +
+
+
+

3.1.0 (2011-04-16)

+
    +
  • Added the "Folders" scan type. (#89)
  • +
  • Fixed a couple of crashes. (#140 #149)
  • +
+
+
+

3.0.2 (2011-03-16)

+
    +
  • Fixed crash after removing marked dupes. (#140)
  • +
  • Fixed crash on error handling. [Windows] (#144)
  • +
  • Fixed crash on copy/move. [Windows] (#148)
  • +
  • Fixed crash when launching dupeGuru from a very long folder name. [Mac OS X] (#119)
  • +
  • Fixed a refresh bug in directory panel. (#153)
  • +
  • Improved reliability of the "Send to Trash" operation. [Linux]
  • +
  • Tweaked Fairware reminders.
  • +
+
+
+

3.0.1 (2011-01-27)

+
    +
  • Restored the context menu which had been broken in 3.0.0. [Mac OS X] (#133)
  • +
  • Fixed a bug where an "unsaved results" warning would be issued on quit even with empty results. (#134)
  • +
  • Removed focus from the cancel button in the progress dialog to avoid accidental cancellations. [Mac OS X] (#135)
  • +
  • Folders added through drag and drop are added to the recent folders list. (#136)
  • +
  • Added a debugging mode. (#132)
  • +
  • Fixed french localization glitches.
  • +
+
+
+

3.0.0 (2011-01-24)

+
    +
  • Re-designed the UI. (#129)
  • +
  • Internationalized dupeGuru and localized it to french. (#32)
  • +
  • Changed the format of the help file. (#130)
  • +
+
+
+

2.12.3 (2011-01-01)

+
    +
  • Fixed bug causing results to be corrupted after a scan cancellation. (#120)
  • +
  • Fixed crash when fetching Fairware unpaid hours. (#121)
  • +
  • Fixed crash when replacing files with hardlinks. (#122)
  • +
+
+
+

2.12.2 (2010-10-05)

+
    +
  • Fixed delta column colors which were broken since 2.12.0.
  • +
  • Fixed column sorting crash. (#108)
  • +
  • Fixed occasional crash during scan. (#106)
  • +
+
+
+

2.12.1 (2010-09-30)

+
    +
  • Re-licensed dupeGuru to BSD and made it Fairware.
  • +
+
+
+

2.12.0 (2010-09-26)

+
    +
  • Improved UI with a little revamp.
  • +
  • Added the possibility to place hardlinks to references after having deleted duplicates. [Mac OS X, Linux] (#91)
  • +
  • Added an option to ignore duplicates hardlinking to the same file. [Mac OS X, Linux] (#92)
  • +
  • Added multiple selection in the "Add Directory" dialog. [Mac OS X] (#105)
  • +
  • Fixed a bug preventing drag & drop from working in the Directories panel. [Windows, Linux]
  • +
+
+
+

2.11.1 (2010-08-26)

+
    +
  • Fixed HTML exporting which was broken in 2.11.0.
  • +
+
+
+

2.11.0 (2010-08-18)

+
    +
  • Added the ability to save results (and reload them) at arbitrary locations.
  • +
  • Improved the way reference files in dupe groups are chosen. (#15)
  • +
  • Remember size/position of all windows between launches. (#102)
  • +
  • Fixed a bug sometimes preventing dupeGuru from reloading previous results.
  • +
  • Fixed a bug sometimes causing the progress dialog to be stuck there. [Mac OS X] (#103)
  • +
  • Removed the Creation Date column, which wasn't displaying the correct value anyway. (#101)
  • +
+
+
+

2.10.1 (2010-07-15)

+ +
+
+

2.10.0 (2010-04-13)

+
    +
  • Improved error messages when files can't be sent to trash, moved or copied.
  • +
  • Added a custom command invocation action. (#12)
  • +
  • Filters are now applied on whole paths. (#4)
  • +
+
+
+

2.9.2 (2010-02-10)

+
    +
  • dupeGuru is now 64-bit on Mac OS X!
  • +
  • Fixed a crash upon quitting when support folder is not present. (#83)
  • +
  • Fixed a crash during sorting. (#85)
  • +
  • Fixed selection glitches, especially while renaming. (#93)
  • +
+
+
+

2.9.1 (2010-01-13)

+
    +
  • Improved memory usage for Contents scans. (#75)
  • +
  • Improved scanning speed when ref directories are involved. (#77)
  • +
  • Show a message dialog at the end of the scan if no duplicates are found. (#81)
  • +
  • Fixed a bug sometimes causing the small files threshold pref to be ignored. [Mac OS X] (#75)
  • +
+
+
+

2.9.0 (2009-11-03)

+
    +
  • Significantly improved speed and memory usage of big contents-based scans.
  • +
  • Added drag & drop support in the Directories panel. (#9)
  • +
  • Fixed a bug causing dupeGuru to be confused if a scanned file was moved during the scan. (#72)
  • +
  • Dropped support for Mac OS X 10.4 (Tiger)
  • +
+
+
+

2.8.2 (2009-10-14)

+
    +
  • Improved directory selection in the Directories panel (Windows). (#56)
  • +
  • Fixed a bug preventing dupeGuru from starting on certain machines (Windows). (#68)
  • +
  • Fixed a crash during very big scans. (#70)
  • +
+
+
+

2.8.1 (2009-10-02)

+
    +
  • Fixed crash with filtering when regular expressions were enabled. (#60)
  • +
  • Fixed crash when setting directories' state. (Mac OS X) (#66)
  • +
  • Fixed crash with Make Reference when certain filters are applied. (Mac OS X) (#55)
  • +
  • Improved error handling during delete/move/copy actions. (#62 #65)
  • +
+
+
+

2.8.0 (2009-09-07)

+
    +
  • Added support for all kinds of bundle (not just applications) (Mac OS X) (#11)
  • +
  • Re-introduced the Export to XHTML feature to Windows. (#14)
  • +
  • Improved Export to XHTML speed. (#14)
  • +
  • Improved Contents scanning speed for large files. (#33)
  • +
  • Improved the grouping algorithm to reduce the number of discarded files in non-exact scans. (#51)
  • +
  • Stopped showing the same file on the 2 sides of the details panel when a ref file is selected. (#50)
  • +
  • Fixed crashes in the Directories panel. (#46)
  • +
+
+
+

2.7.3 (2009-06-20)

+
    +
  • +
    Fixed bugs with selection being jumpy during "Make Reference" actions and Power Marker
    +
    switches. (#3)
    +
    +
  • +
  • Fixed crash happening when a file with non-roman characters couldn't be analyzed. (#30)
  • +
  • Fixed crash sometimes happening during the file collection phase in scanning. (#38)
  • +
  • Restored double-click and right-click behavior lost in the PyQt move (Windows). (#34 #35)
  • +
+
+
+

2.7.2 (2009-06-10)

+
    +
  • Fixed an occasional crash on Copy/Move operations. (#16)
  • +
  • Added automatic exclusion for sensible folders (like system folders). (#20)
  • +
  • Fixed an occasional crash when application files were part of the results (Mac OS X). (#25)
  • +
+
+
+

2.7.1 (2009-05-29)

+
    +
  • Fixed a bug causing crashes when having application files in the results.
  • +
  • Fixed a bug causing a GUI freeze at the beginning of a scan with a lot of files.
  • +
  • Fixed a bug that sometimes caused a crash when an action was cancelled, and then started again.
  • +
+
+
+

2.7.0 (2009-05-25)

+
    +
  • Converted the Windows GUI to Qt.
  • +
  • Improved the reliability of the scanning process.
  • +
+
+
+

2.6.1 (2009-03-27)

+
    +
  • Fixed an occasional crash caused by permission issues.
  • +
  • +
    Fixed a bug where the "X discarded" notice would show a too large number of discarded
    +
    duplicates.
    +
    +
  • +
+
+
+

2.6.0 (2008-09-10)

+
    +
  • Added a small file threshold preference.
  • +
  • Added a notice in the status bar when matches were discarded during the scan.
  • +
  • Improved duplicate prioritization (smartly chooses which file you will keep).
  • +
  • Improved scan progress feedback.
  • +
  • Improved responsiveness of the user interface for certain actions.
  • +
+
+
+

2.5.4 (2008-08-10)

+
    +
  • Improved the speed of results loading and saving.
  • +
  • Fixed a crash sometimes occurring during duplicate deletion.
  • +
+
+
+

2.5.3 (2008-07-08)

+
    +
  • Improved unicode handling for filenames. dupeGuru will now find a lot more duplicates if your files have non-ascii characters in it.
  • +
  • Fixed "Clear Ignore List" crash in Windows.
  • +
+
+
+

2.5.2 (2008-01-10)

+
    +
  • Improved the handling of low memory situations.
  • +
  • Improved the directory panel. The "Remove" button changes to "Put Back" when an excluded directory is selected.
  • +
  • Improved scan, delete and move speed in situations where there were a lot of duplicates.
  • +
  • Fixed occasional crashes when moving bundles (such as .app files).
  • +
  • Fixed occasional crashes when moving a lot of files at once.
  • +
+
+
+

2.5.1 (2007-11-22)

+
    +
  • Added the "Remove empty folders" option.
  • +
  • Fixed results load/save issues.
  • +
  • Fixed occasional status bar inaccuracies when the results are filtered.
  • +
+
+
+

2.5.0 (2007-09-15)

+
    +
  • Added post scan filtering.
  • +
  • Fixed issues with the rename feature under Windows
  • +
  • Fixed some user interface annoyances under Windows
  • +
+
+
+

2.4.8 (2007-04-14)

+
    +
  • Improved UI responsiveness (using threads) under Mac OS X.
  • +
  • Improved result load/save speed and memory usage.
  • +
+
+
+

2.4.7 (2007-03-10)

+
    +
  • Fixed a "bad file descriptor" error occasionally popping up.
  • +
  • Fixed a bug with non-latin directory names.
  • +
+
+
+

2.4.6 (2007-02-10)

+
    +
  • Added Re-orderable columns. In fact, I re-added the feature which was lost in the C# conversion in 2.4.0 (Windows).
  • +
  • Changed the behavior of the scanning engine when setting the hardness to 100. It will now only match files that have their words in the same order.
  • +
  • Fixed a bug with all the Delete/Move/Copy actions with certain kinds of files.
  • +
+
+
+

2.4.5 (2007-01-11)

+
    +
  • Fixed a bug with the Move action.
  • +
+
+
+

2.4.4 (2007-01-07)

+
    +
  • Fixed a "ghosting" bug. Dupes deleted by dupeGuru would sometimes come back in subsequent scans (Windows).
  • +
  • Fixed bugs sometimes making dupeGuru crash when marking a dupe (Windows).
  • +
  • Fixed some minor visual glitches (Windows).
  • +
+
+
+

2.4.3 (2006-12-08)

+
    +
  • Fixed a mishandling of ".app" files (OS X).
  • +
  • Fixed a bug preventing files from "reference" directories to be displayed in blue in the results (Windows).
  • +
  • Fixed a bug preventing some files to be sent to the recycle bin (Windows).
  • +
  • Fixed a bug in the packaging preventing certain Windows configurations to start dupeGuru at all.
  • +
+
+
+

2.4.2 (2006-11-18)

+
    +
  • Fixed a bug with directory states.
  • +
+
+
+

2.4.1 (2006-11-15)

+
    +
  • Fixed a bug causing the ignore list not to be saved.
  • +
  • Fixed a bug sometimes making delete and move operations stall.
  • +
+
+
+

2.4.0 (2006-11-10)

+
    +
  • Changed the Windows interface. It is now .NET based.
  • +
  • Added an auto-update feature to the windows version.
  • +
  • Changed the way power marking works. It is now a mode instead of a separate window.
  • +
  • Changed the "Size (MB)" column for a "Size (KB)" column. The values are now "ceiled" instead of rounded. Therefore, a size "0" is now really 0 bytes, not just a value too small to be rounded up. It is also the case for delta values.
  • +
  • Removed the min word length/count options. These came from Mp3 Filter, and just aren't used anymore. Word weighting does pretty much the same job.
  • +
+
+
+

2.3.4 (2006-11-07)

+
    +
  • Improved speed and memory usage of the scanning engine, again. Does it mean there was a lot of improvements to be made? Nah...
  • +
+
+
+

2.3.3 (2006-11-02)

+
    +
  • Improved speed and memory usage of the scanning engine, especially when the scan results in a lot of duplicates.
  • +
  • Now I wonder if Sparkle is going to work well...
  • +
+
+
+

2.3.2 (2006-10-16)

+
    +
  • Added an auto-update feature in the Mac OS X version (with Sparkle).
  • +
  • Fixed a bug preventing some duplicate reports to be created correctly under Windows.
  • +
+
+
+

2.3.1 (2006-10-02)

+
    +
  • Fixed a bug preventing some duplicates to be found, especially when scanning lots of files.
  • +
+
+
+

2.3.0 (2006-09-22)

+
    +
  • Added XHTML export feature.
  • +
+
+
+

2.2.10 (2006-08-31)

+
    +
  • Added sticky columns.
  • +
  • Fixed an issue with file caching between scans.
  • +
  • Fixed an issue preventing some duplicates from being deleted/moved/copied.
  • +
+
+
+

2.2.9 (2006-08-27)

+
    +
  • Fixed an issue with ignore list and unicode.
  • +
  • Fixed an issue with file attribute fetching sometimes causing dupeGuru to crash.
  • +
  • Fixed an issue in the directories panel under Windows.
  • +
+
+
+

2.2.8 (2006-08-17)

+
    +
  • Fixed an issue in the duplicate seeking engine preventing some duplicates to be found.
  • +
+
+
+

2.2.7 (2006-08-12)

+
    +
  • Improved unicode support.
  • +
  • Improved the "Reveal in Finder" ("Open Containing Folder" in Windows) feature so it selects the file in the folder it opens.
  • +
+
+
+

2.2.6 (2006-08-07)

+
    +
  • Improved the ignore list system.
  • +
  • dupeGuru is now a Universal application on Mac OS X.
  • +
+
+
+

2.2.5 (2006-07-26)

+
    +
  • Improved application (.app) dupe detection on Mac OS X.
  • +
  • Fixed an issue that occasionally made dupeGuru crash on startup.
  • +
+
+
+

2.2.4 (2006-06-27)

+
    +
  • Fixed an issue with Move and Copy features.
  • +
+
+
+

2.2.3 (2006-06-15)

+
    +
  • Improved duplicate scanning speed.
  • +
  • Added a warning that a file couldn't be renamed if a file with the same name already exists.
  • +
+
+
+

2.2.2 (2006-06-07)

+
    +
  • Added "Rename Selected" feature.
  • +
  • Fixed some minor issues with "Reload Last Results" feature.
  • +
  • Fixed ignore list issues.
  • +
+
+
+

2.2.1 (2006-05-22)

+
    +
  • Fixed occasional progress bar woes under Windows.
  • +
  • Fixed a bug in the registration system under Windows.
  • +
  • Nothing has been changed in the Mac OS X version, but I want to keep version in sync.
  • +
+
+
+

2.2.0 (2006-05-10)

+
    +
  • Added destination path re-creation options.
  • +
  • Added an ignore list.
  • +
  • Changed the main icon.
  • +
  • Improved dramatically the delta values feature.
  • +
+
+
+

2.1.2 (2006-04-18)

+
    +
  • Added the "Match similar words" option.
  • +
  • Fixed Power marking issues under Mac.
  • +
+
+
+

2.1.1 (2006-04-14)

+
    +
  • Added the "Display delta values" option.
  • +
  • Improved Power marking sorting speed under Mac.
  • +
  • Fixed Power marking sorting issues.
  • +
+
+
+

2.1.0 (2006-04-03)

+
    +
  • Added the Power Marker feature.
  • +
  • Fixed a column sorting bug. The results would sometimes lose their sort order.
  • +
  • Fixed a bug with the Make Reference feature. The results sometimes wasn't correctly refreshed after the reference switch.
  • +
+
+
+

2.0.1 (2006-03-23)

+
    +
  • Fixed an issue occasionally occurring when trying to reload results from removable media that is no longer present.
  • +
+
+
+

2.0.0 (2006-03-17)

+
    +
  • Complete rewrite.
  • +
  • Now runs on Mac OS X.
  • +
+
+
+

1.0.0 (2004-09-24)

+
    +
  • Initial release.
  • +
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/hy/faq.html b/help/hy/faq.html new file mode 100644 index 00000000..b0c30b8f --- /dev/null +++ b/help/hy/faq.html @@ -0,0 +1,102 @@ + + + + + + + + Հաճախ Տրվող Հարցեր — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + +
+ + +
+

Հաճախ Տրվող Հարցեր

+
+

Ի՞նչ է dupeGuru-ը:

+
+
+

Ի՞նչն է այս ծրագիրը առանձնացնում մյուս նմանատիպ ծրագրերից:

+

Ստուգելու համակարգը չափազանց նուրբ է: Կարող եք ինքներդ հարմարեցնել այն՝ ստանալու համար այն արդյունքը, ինչը որ Ձեզ պետք է: Կարող եք լրացուցիչ կարդալ այս մասին dupeGuru-ի կարգավորման ընտրանքներում՝ Կարգավորումների էջում:

+
+
+

Ո՞րքանով է անվտանգ օգտագործելու dupeGuru-ը:

+

Շատ անվտանգ է: dupeGuru-ը նախագծվել է՝ համոզված լինելու համար, որ Դուք չջնջեք այն ֆայլերը, որոնք չպետք է ջնջեք: Նախ, կա հղմամբ համակարգային թղթապանակ, որը հնարավորություն է տալիս Ձեզ որոշելու թղթապանակներ, որտեղ Դուք բացարձակ չեք ցանկանում, որ dupeGuru-ն հնարավորություն տա Ձեզ ջնջելու ֆայլերը այստեղից, և ապա կա խմբի հղմամբ համակարգային համակարգ, որը համոզմունք է ստեղծում, որ Դուք միշտ պետք է պահեք գոնե մեկ անդամ կրկնօրինակվող խմբի:

+
+
+

Ո՞րոն եք dupeGuru-ի լիցենզիայի սահմանափակումները:

+

Փորձնական եղանակում, Դուք կարող եք միայն կատարել գործողություններ 10 կրկնօրինակների հետ միաժամանակ: Ծրագրի +Անվճար տարբերակում mode, այնուհանդերձ չկան էական սահմանափակումներ:

+
+
+

Ես ունեմ թղթապանակ, որտեղից ես իրապես չեմ ցանկանում ջնջել ֆայլեր:

+

Եթե Դուք ցանկանում եք համոզված լինել, որ dupeGuru-ն երբեք չի ջնջի ֆայլ կոնկրետ թղթապանակից, համոզված եղեք, որ տվել եք կարգը Հղման Թղթապանակի ընտրություն:

+
+
+

Ի՞նչ է սա '(X վնասված)'՝ նշված դրության տողում:

+

Որոշ դեպքերում, որոշ համընկնումներ ներառված չեն վերջնական արդյունքում երկրորդական պատճառներով: Եկեք նայենք կոնկրետ օրինակի վրա: Մենք ունենք 3 ֆայլ. A, B և C: Մենք ստուգում ենք այն՝ օգտագործելով ֆիլտրի ցածր մակարդակով: Ստուգիչը արդեն որոշել է, որ A համընկնումները B-ի, A-ի համընկնումները C-ին, բայց B-ն չի համընկնում C-ին: Այստեղ dupeGuru-ն ունի մի շարք խնդիրներ: Այն չի կարող ստեղծել կրկնօրինակվող խումբ A, B և C իրենում, որովհետև ոչ բոլոր ֆայլերն են խմբում համընկնում միմյանց: Այն կարող է ստեղծել 2 խումբ. մեկ A-B խումբ և ապա մեկ A-C խումբ, բայց այն չի լինի՝ անվտանգության նկատառումներից ելնելով: Եկեք մտածենք սրա մասին. Եթե B-ն չի համընկնում C-ին, հնարավոր է դա նշանակում է, որ անգամ B, C կամ երկուսն էլ իրականում կրկնօրինակներ չեն: Եթե այնտեղ լինեն 2 խմբեր (A-B և A-C), ապա Դուք պետք է ջնջեք B-ն և C-ն: Եթե դրանցից մեկը կրկնօրինակ չէ, ապա դա այն չէ, ինչը որ Ձեզ պետք է, այնպես չէ՞: Այսպիսով, ինչ dupeGuru չի մի դեպքում նման սրան՝ բացառելով A-C համընկնումը (և ավելացնում է տեղեկացում դրության տողում): Այսպիսով, եթե Դուք ջնջեք B-ն և վերսկսեք ստուգումը, ապա կունենք A-C համընկնում հաջորդ արդյունքներում:

+
+
+

Ես ցանկանում եմ նշել բոլոր ֆայլերը որոշված թղթապանակից: Ի՞նչ կարող եմ ես անել:

+

Միացնել Միայն Սխալները եղանակը և սեղմեք թղթապանակի սյանը՝ դասավորելու համար կրկնօրինակները ըստ թղթապանակների: Հետագայում հեշտ կլինի ընտրելու բոլոր կրկնօրինակները նույն թղթապանակից և ապա սեղմեք Space՝ ընտրելու ահմար բոլոր կրկնօրինակները:

+
+
+

Ես փորձում եմ կրկնօրինակները ուղարկել Աղբարկղ, բայց dupeGuru-ն ինձ ասում է, որ չես կարող: Ինչու՞: Ի՞նչ կարող եմ ես անել:

+

Շատ ժամանակ, պատճառը, թե ինչու dupeGuru-ն չի կարողանում տեղափոխել ֆայլերը Աղբարկղ, կայանում է ֆայլի լիազորությունների մեջ: Դուք պետք է գրեք լիազորությունները ֆայլերում, որոնք որ ցանկանում եք ուղարկել Աղբարկղ: Եթե Ձեզ անծանոթ է Հրամանի տողը, ապա Դուք կարող եք օգտագործել լրացուցիչ գործիքներ, ինչպես օրինակ BatChmod լիազորումները նշելու համար:

+

Եթե dupeGuru-ն դեռ շարունակում է խնդիրներ առաջ բերել կապված լիազորությունների հետ, ապա կան խնդիրներ կապված՝ "Տեղափոխել նշվածը..." որպես շրջանցիկ խորամանկություն: Ուստի ֆայլերը Աղբարկ տեղափոխելիս Դուք ուղարկում եք այն ժամանակավոր թղթապանակ "Տեղափոխել նշվածը..." գործողությամբ և ապա Դուք կջնջեք այդ թղթապանակը ձեռադիր;

+

Եթե այս ամենը ձախողվի, կապնվեք HS աջակցության թիմի հետ, մենք կփորձեք օգնել Ձեզ:

+
+
+

Todo

+

This FAQ qestion is outdated, see english version.

+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/hy/folders.html b/help/hy/folders.html new file mode 100644 index 00000000..26d36953 --- /dev/null +++ b/help/hy/folders.html @@ -0,0 +1,83 @@ + + + + + + + + Թղթապանակի ընտրություն — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + +
+ + +
+

Թղթապանակի ընտրություն

+

Առաջին թղթապանակը, որ Դուք տեսնում եք dupeGuru-ն բացելիս դա թղթապանակի ընտրությունն է: Այս պատուհանը պարունակում է թղթապանակների ցանկը, որոնք կստուգվեն Ստուգել սեղմելիս:

+

Այս պատուհանը շատ հեշտ է օգտագործել: Եթե ցանկանում եք ավելացնել թղթապանակ, ապա սեղմեք + կոճակը: Եթե մինչ այդ ավելացնեք թղթապանակը, ապա կերևա ավելացված վերջին թղթապանակների ցանկը: Կարող եք սեղմել նրանցից մեկի վրա՝ ավելացնելու համար ուղղակի Ձեր ցանկում: Եթե սեղմեք հայտնվող պատուհանի առաջին ֆայլին՝ Ավելացնել նոր թղթապանակ..., ապա Ձեզ հարցում կկատարվի թղթապանակ ավելացնելու մասին: Եթե երբեք չեք ավելացրել թղթապանակ, ապա ոչ մի ընտրացանկ չի երևա և Ձեզ ուղղակի հարցում կարվի նոր թղթապանակ ավելացնելու մասին:

+

Այլընտրանքյին ճանապարհով թղթապանակներ կարող եք ավելացնել պարզապես դրանք գցելով ցանկում:

+

Թղթապանակը հեռացնելու համար ընտրեք թղթապանակը, սեղմեք -: Եթե ընտրված է ենթաթղթպանակը, երբ Դուք սեղմում եք կոճակին, ընտրված թղթապանակը կնշվի որպես բացառված (նայեք այստեղ)՝ ջնջվելու փոխարեն:

+
+

Թղթապանակի վիճակը

+

Յուրաքանչյուր թղթապանակ կարող է լինել հետևյալ 3 եղանակներից մեկում.

+
    +
  • Նորմալ. Այս թղթապանակում գտնված կրկնօրինակները կարող են ջնջվել:
  • +
  • Հղված. Կրկնօրինակներ են գտնվել այս թղթապանակում, որոնք չեն կարող ջնջվել: Ֆայլերը այս թղթապանակից կարող են միայն ավարտվել հղում դիրքով խմբում: Եթե մեկ ֆայլից ավելի են հղման թղթապանակների հղումները, ապա միայն մեկը կպահվի: Մնացածը կջնջվեմ խմբից:
  • +
  • Բացառված. Ֆայլերը այս թղթապանակում կներառվեն ստուգման մեջ:
  • +
+

Թղթապանակի հիմնական վիճակը, իհարկե՛ Նորմալ է: Կարող եք օգտագործել Հղված վիճակը թղթապանակի համար, եթե ցանկանում եք համոզված լինել, որ ոչ մի ֆայլ չի ջնջվի:

+

Եթե նշել եք թղթապանակի վիճակը, բոլոր ենթաթղթապանակները միանգամից կժառանգեն այս վիճակը, եթե վիճակը պարզորոշ տրված է թղթապանակի կարգում:

+
+

Todo

+

Add iPhoto/Aperture/iTunes libraries notes

+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/hy/genindex.html b/help/hy/genindex.html new file mode 100644 index 00000000..3ce719e2 --- /dev/null +++ b/help/hy/genindex.html @@ -0,0 +1,58 @@ + + + + + + + + + Index — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + +
+ + + +

Index

+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/hy/index.html b/help/hy/index.html new file mode 100644 index 00000000..17dbecd2 --- /dev/null +++ b/help/hy/index.html @@ -0,0 +1,93 @@ + + + + + + + + dupeGuru help — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + +
+

dupeGuru help

+

Չնայած dupeGuru-ն կարող է հեշտությամբ օգտագործվել առանց օգնության, այնուհանդերձ եթե կարդաք այս ֆայլը, այն մեծապես կօգնի Ձեզ ընկալելու ծրագրի աշխատանքը: Եթե Դուք նայում եք ձեռնարկը կրկնօրինակների առաջին ստուգման համար, ապա կարող եք ընտրել Արագ Սկիզբ հատվածը:

+

Շատ լավ միտք է պահելու dupeGuru թարմացված: Կարող եք բեռնել վեբ կայքի համապատասխան էջից homepage:

+

Պարունակությունը.

+ +
+
+

Indices and tables

+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/hy/objects.inv b/help/hy/objects.inv new file mode 100644 index 00000000..fd7ecde2 Binary files /dev/null and b/help/hy/objects.inv differ diff --git a/help/hy/preferences.html b/help/hy/preferences.html new file mode 100644 index 00000000..66db5c23 --- /dev/null +++ b/help/hy/preferences.html @@ -0,0 +1,81 @@ + + + + + + + + Կարգավորումներ — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + +
+ + +
+

Կարգավորումներ

+

Կարող է ուղղել ֆայլի տեսակը. Եթե ընտրում եք այս վանդակը, ապա կրկնօրինակվող խմբերը կթույլատրվեն ունենալու տարբեր ընդլայնումներ: Եթե չընտրեք, ապա դրանք չեն լինի!

+

Անտեսել կրկնօրինակների հղումը նույն ֆայլին file: Եթե այս ընտրանքը միացված է, dupeGuru-ն կստուգի կրկնօրինակները՝ տեսնելու համար արդյոք դրանք հղվում են նույնին inode: Եթե այո, ապա դրանք չեն որոշվի որպես կրկնօրինակ: (Միայն OS X և Linux-ում)

+

Ֆիլտրելիս օգտագործել կանոնավոր սահմանումներ. Եթե ընտրեք սա, ապա ֆիլտրման հնարավորությունը կդիմի ֆիլտրման հերթին, ինչպես որ կանոնավոր սահմանում: Դրա բացատրությունը դուրս կգա այս փաստաթղթի շրջանակից: Ավելին կարող եք կարդալ այստեղ՝ regular-expressions.info:

+

Ջնջել դատարկ թղթապանակները ջնջելուց կամ տեղափոխելուց. Երբ այս ընտրանքը միացված է, թղթապանակները կջնջվեն, երբ որ ֆայլը ջնջվի կամ տեղափոխվի և թղթապանակը դատարկ լինի:

+

Պատճենել և տեղափոխել. Որոշում է, թե Պատճենելու և Տեղափոխելու գործողությունները (գործողություն ընտրացանկից):

+
    +
  • Տեղադրությունից աջ. Բոլոր ֆայլերը կուղարկվեն ընտրված տեղ՝ առանց փորձելու վերստեղծելու աղբյուրի ճանապարհը բոլորի համար:
  • +
  • Վերստեղծել հարաբերական ճանապարհը. Աղբյուր ֆայլի ճանապարհը կվերստեղծվի նշանակված թղթապանակում՝ խորքայինից մեկ աստիճան վեր՝ Թղթապանակներ վահանակից: Օրինակ՝ եթե ավելացնեք``/Users/foobar/SomeFolder`` Թղթապանակներ վահանակ և տեղափոխեք /Users/foobar/SomeFolder/SubFolder/SomeFile.ext նշանակության թղթապանակ /Users/foobar/MyDestination, ֆայլի վերջնական տեղավորությունը կլինի /Users/foobar/MyDestination/SubFolder (SomeFolder բաժանվել է աղբյուր ճանապարհից վերջնական տեղադրությունում):
  • +
  • Վերստեղծել հարաբերական ճանապարհը. Աղբյուր ֆայլի ճանապարհը կվերստեղծվի նշանակված թղթապանակում՝ իր հարթությունում: Օրինակ՝ եթե տեղափոխեք /Users/foobar/SomeFolder/SubFolder/SomeFile.ext նշանակության թղթապանակ /Users/foobar/MyDestination, ֆայլի վերջնական տեղավորությունը կլինի /Users/foobar/MyDestination/Users/foobar/SomeFolder/SubFolder:
  • +
+

Ամեն դեպքում, dupeGuru լավ է հարթում անունների կոնֆլիկտը՝ նախապատրաստելով նշանակության ֆայլի անվան թիվը՝ եթե ֆայլը արդեն առկա է նշված տեղում:

+

Ընտրված հրամանը. Այս կարգավորումը որոշում է հրամանը, որը կկանչվի "Կանչել Ընտրված հրամանը" գործողությամբ: Կարող եք կանչել ցանկացած արտաքին ծրագիր՝ այս գործողությամբ: Սա կարող է օգտակար լինել եթե օրինակ փոխարենը ունեք տվյալների փոխանցման լավ ծրագիր:

+

Հրամանի տեսակը նույնն է, ինչ Դուք կգրեք Հրամանի տողում, բացառությամբ որտեղ կան 2 լրացումներ. %d և %r: Այս լրացումները կվերագրվեն ընտրված զոհի (%d) ճանապարհով և ընտրված զոհի հղման ֆայլով (%r):

+

Եթե կատարելի ֆայլի ճանապարհը պարունակում է բացատներ, ապա պետք է փակեք այն "" չակերտներով: Նաև պետք է փակեք լրացումները չակերտներով, որովհետև շատ հնարավոր է, որ զոհի ճանապարհները և հղումները կպարունակեն բացատներ: Ահա ընտրված հրամանի օրինակ՝

+
"C:\Program Files\SuperDiffProg\SuperDiffProg.exe" "%d" "%r"
+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/hy/quick_start.html b/help/hy/quick_start.html new file mode 100644 index 00000000..8d56102d --- /dev/null +++ b/help/hy/quick_start.html @@ -0,0 +1,75 @@ + + + + + + + + Արագ Սկիզբ — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + +
+ + +
+

Արագ Սկիզբ

+

Արագ սկսելու համար dupeGuru-ն, պարզապես կատարեք ստանդարտ ստուգում՝ օգտագործելով ծրագրային կարգավորումները:

+
    +
  • Բացել dupeGuru-ն:
  • +
  • Ավելացնել թղթապանակներ՝ ստուգելու համար նաև վերցնել & գցելը կամ "+" կոճակը:
  • +
  • Սեղմեք Ստուգել:
  • +
  • Սպասեք, մինչ ստուգումը կավարտվի:
  • +
  • Նայեք ցանկացած կրկնօրինակին (Ֆայլեր, որոնք նշվել են) և ստուգվել, իրականում կրկնօրինակել խմբի հղմանը (Ֆայլը կրկնօրինակելուց առաջ չի նշվում և ընտրված չէ):
  • +
  • Եթե ֆայլը սխալ կրկնօրինակ է, ապա ընտրեք այն և սեղմեք Գործողություններ-->Հեռացնել ընտրվածը Արդյունքներից:
  • +
  • Եթե համոզված եք, որ կրկնօրինակը արդյունքներում կա, ապա սեղմեք Խմբագրել-->Նշել բոլորը, և ապա Գործողություններ-->Ուղարկել Նշվածը Աղբարկղ:
  • +
+

Սա միայն բազային ստուգում է: Կան բազմաթիվ կարգավորումներ, որոնք հնարավորություն են տալիս նշելու տարբեր արդյունքներ և մի քանի եղանակներ արդյունքների փոփոխման: Մանրամասների համար կարդացեք Օգնության ֆայլը:

+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/hy/reprioritize.html b/help/hy/reprioritize.html new file mode 100644 index 00000000..65abf95f --- /dev/null +++ b/help/hy/reprioritize.html @@ -0,0 +1,83 @@ + + + + + + + + Վերաառաջնայնության կրկնօրինակներ — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + +
+ + +
+

Վերաառաջնայնության կրկնօրինակներ

+

dupeGuru-ը փորձում է որոշել, թե որ կրկնօրինակները պետք է գնան յուրաքանչյուր խմբի դիրքում, +բայց երբեմն սխալ է ստանում: Շատ դեպքերում, խելամիտ դասավորումը "Դելտա նշանակության" +և "Միայն սխալները" ընտրանքների ավելացնելով "Դարձնել ընտրվածը հղում" գործողության խորամանկություն է, բայց +երբեմն, պահանջվում են ավելի լավ ընտրանքներ: Ահա այստեղ է, որ վերաառաջնայնավորման պատուհանը բացվում է: +Կարող եք կանչել այն "Վերաառաջնայնավորման արդյունքները" կետից՝ "Գործողություններ" ընտրացանկից:

+

Այս պատուհանը հնարավորություն է տալիս Ձեզ ընտրելու չափանիշներ՝ հղման սխալին համապատասխան և կընտրվի +յուրաքանչյուր սխալի խումբը: Հասանելի չափանիշների ցանկը ձախում է և Ձեր ընտրած չափանիշների ցանկը գտնվում է +աջում:

+

Չափանիշն դա բաժինն է, որը հետևում է փաստարկին: Օրինակ՝ "Չափը (Բարձրագույն)" նշանակում է, որ սխալը +հետևում է մեծագույն չափի հաղթողին: "Թղթապանակը (/foo/bar)" նշանակում է, որ սխալները թղթապանակում կհաղթեն: Ավելացնելու համար +փաստարկ ամենաաջ մասում, նախ ընտրեք բաժինը, ապա ընտրեք +ենթափաստարկ հետևյալ ցանկում և ապա սեղմեք կոճակի սլաքի աջ մասում:

+

Ցանկի կարգը աջից շատ կարևոր է (կարող եք վերակարգավորել ֆայլերը վերցնել և գցելու միջոցով): Երբ +սխալի տեղորոշումը հղման դիրքում է, ապա օգտագործվում է առաջին փաստարկը: Եթե դա կապված է, ապա երկրորդ +փաստարկն է օգտագործվում և այլն և այլն: Օրինակ, եթե Ձեր փաստարկները "Չափը (բարձրագույն)" են և ապա +"Ֆայլի անունը (Չի ավարտվում թվով)", ապա հղման ֆայլը, որը կընտրվի խմբում, ապա կլինի +մեծագույն ֆայլը և եթե երկու կամ ավելի ֆայլեր ունեն նույն չափը, ապա մեկը ունի ֆայլի անուն, որը +չի ավարտվում թվով, կօգտագործվի: Երբ փաստարկի արդյունքը կապված է, կարգը, որի սխալները +նախկինում էին, խումբը պետք է օգտագործվի:

+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/hy/results.html b/help/hy/results.html new file mode 100644 index 00000000..ec026c05 --- /dev/null +++ b/help/hy/results.html @@ -0,0 +1,152 @@ + + + + + + + + Արդյունքները — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + +
+ + +
+

Արդյունքները

+

Երբ dupeGuru-ն ավարտի կրկնօրինակների ստուգումը, կցուցադրի արդյունքները կրկնօրինակ խմբերի ցանկում:

+
+

Կրկնօրինակ խմբերի մասին

+

Կրկնօրինակման խումբը դա ֆայլերի խումբ է, որոնք բոլորը համընկնում են միմյանց: Ամեն խումբ ունի իր հղվող ֆայլը և մեկ կամ մի քանի կրկնօրինակ ֆայլեր: Հղվող ֆայլը դա խմբի առաջին ֆայլն է: Այն ընտրված չէ, նրանից ցածր և փոխարեն կրկնօրինակ ֆայլերի:

+

Կարող եք նշել կրկնօրինակ ֆայլերը, բայց երբեք չեք կարող նշել հղվող ֆայլը խմբում: Սա երկրորդ պատճառն է՝ կանխելու dupeGuru-ին ջնջելու ոչ միայն կրկնօրինակ ֆայլերը, այլև դրանց հղումները: Համոզվա՞ծ եք, չէ, որ պետք չէ անել դա:

+

Ինչն է որոշում, թե որ ֆայլերը հղմամբ են և որ ֆայլերը կրկնօրինակ են՝ թղթապանակի նախնական վիճակում: Ֆայլը հղվող թղթապանակից միշտ հղվում է կրկնօրինակի խմբում: Եթե բոլոր ֆայլերը նորմալ թղթապանակից են, ապա չափն է որոշում, թե որ ֆայլը կլինի կրկնօրինակ խմբի հղումը: dupeGuru-ն ընդունում է, որ Դուք կցանկանաք պահել մեծ ֆայլերը, ուստի դրանք կտեղադրվեն հղման խմբում:

+

Կարող եք փոխել հղման ֆայլը խմբում ձեռադիր: Դա անելու համար ընտրեք կրկնօրինակ ֆայլը և սեղմեք Գործողություններ-->Դարձնել ընտրվածը հղմամբ:

+
+
+

Նայել արդյունքները

+

Չնայած պարզապես կարող եք սեղմել Խմբագրել-->Նշել բոլորը և ապա Գործողություններ-->Ուղարկել նշվածը Աղբարկղ արագորեն ջնջելու համար բոլոր կրկնօրինակ ֆայլերը արդյունքներից, միշտ խորհուրդ է տրվում նախ նայել կրկնօրինակները և հետո միայն ջնջել:

+

Օգնելու համար Ձեզ նայելու արդյունքները, կարող եք օգտագործել Մանրամասների վահանակը: Այս վահանակը ցուցադրում է բոլոր մանրամասները ընտրված ընթացիկ ֆայլի, ինչպես նաև հղման մանրամասները: Սա շատ հարմար է արագորեն որոշելու, թե արդյոք կրկնօրինակը իրոքից կրկնօրինակ է, թե ոչ: Կարող եք նաև կրկնակի սեղմեք ֆայլի վրա՝ բացելու համար այն նրա հետ ասոցիացված ծրագրով:

+

Եթե ունեք շատ սխալ կրկնօրինակներ, ապա ճիշտ կրկնօրինակները (Եթե Ձեր ֆիլտրի խստությունը շատ է ցածր) որոշելու լավագույն եղանակը դրանք նայելն է, ընտրեք ճիշտ կրկնօրինակները և ապա սեղմեք Գործողություններ-->Ուղարկել նշվածները Աղբարկղ: Եթե իսկական կրկնօրինակները ավելի շատ են, քան սխալները, ապա կարող եք օգտագործել Գործողություններ-->Ջնջել նշվածները արդյունքներից:

+
+
+

Նշում և Ընտրում

+

նշվածը կրկնօրինակ է՝ նշված նշանով, որը ընտրվում է: ընտրվածը կրկնօրինակ է, որը ընդգծվում է կամ առանձնացվում է: Ընտրելու բազմակի եղանակները կարող են կատարվել dupeGuru-ում ստանդարտ ճանապարհով (Shift/Command/Control սեղմամբ): կարող եք փոփոխել բոլոր ընտրված կրկնօրինակների վիճակը՝ սեղմելով space:

+
+
+

Ցուցադրել Միայն Սխալները

+

Եթե այս ընտրանքը միացված է, ապա կրկնօրինակները ցուցադրվում են առանց իրենց համապատասխան հղվող ֆայլի։ Կարող եք ընտրել, նծել կամ դասավորել այս ցանկը, ինչպես օոր նորմալ եղանակում։

+

dupeGuru-ի արդյունքները, երբ այն նորմալ եղանակում է, դասավորվում են համաձայն կրկնօրինակվող խմբերի' հղվող ֆայլի ։ Սա նշանակում է, որ եթե Դուք ցանկանաք, օրինակի համար, նշել բոլոր կրկնօրինակները "exe" ընդլայնմամբ, ապա չեք կարող պարզապես դասավորել արդյունքները ըստ "Տեսակի"՝ ունենալու համար բոլոր exe կրկնօրինակները միասին, որովհետև խումբը կարող է կազմված լինի մեկից ավելի ֆայլերից։ Ահա այստեղ է, որ աշխատում է Միայն Սխալները եղանակը։ Նշելու համար բոլոր "exe" կրկնօրինակները, Դուք պարզապես պետք է՝

+
    +
  • Միացնեք Միայն Սխալները եղանակը։
  • +
  • Ավելացնեք "Տեսակը" սյունը՝ "Սյուներ" ընտրացանկին։
  • +
  • Սեղմեք "Տեսակը" սյանը՝ դասավորելու համար ցանկը ըստ տեսակի։
  • +
  • Տեղադրել "exe" տեսակի առաջին կրկնօրինակը։
  • +
  • Ընտրեք այն։
  • +
  • Պտտեք ներքև ցանկում՝ տեղադրելու համար "exe" տեսակի վերջին կրկնօրինակը։
  • +
  • Սեղմած պահեք Shift-ը և սեղմեք նրա վրա։
  • +
  • Սեղմեք Space՝ նշելու համար բոլոր կրկնօրինակները։
  • +
+
+
+

Դելտա նշանակությունները

+

Եթե միացնեք սա, որոշ սյուներ կցուցադրվեն նշանակություն՝ հարաբերական կրկնօրինակների հղմանը՝ բացարձակ նշանակությունների փոխարեն։ Այս դելտա նշանակությունները նաև կցուցադրվեն տարբեր գույներով, ուստի կարող եք դրանք հեշտությամբ տեսնել։ Օրինակ՝ եթե կրկնօրինակը 1.2 ՄԲ է և եթե նրա հղումը 1.4 ՄԲ է, ապա Չափը սյունում կցուցադրվի -0.2 ՄԲ։

+
+
+

Միայն Սխալները և Դելտա նշանակությունները

+

Միայն Սխալները եղանակը բացում է իր իսկական ուժը, երբ Դուք օգտագործում եք այն Դելտա նշանակությունների հետ։ Երբ միացնեք այն, բացարձակ նշանակությունների փոխարեն կցուցադրվեն հարաբերական նշանակությունները։ Այսպիսով օրինակ, եթե ցանկանում եք արդյունքներից հեռացնել բոլոր կրկնօրինակները, որոնք 300 Կբ-ից մեծ են իրենց հղումներից, ապա չեք կարող դասավորել միայն սխալները արդյունքները ըստ չափի, այդ դեպքում ընտրեք բոլոր կրկնօրինակները, որոնք -300 են Չափը սյունից, ջնջեք դրանք և ապա արեք նույն գործողությունը նաև 300-ից բարձր կրկնօրինակների համար՝ ցանկի ներքևում։

+

Կարող եք նաև օգտագործել սա՝ փոխելու համար կրկնօրինակման ցանկի հղման առաջնայնությունը։ Նոր ստուգումը կատարելուց հետո, եթե չլինեն հղվող թղթապանակներ, հղվող ֆայլը ամեն խմբի կլինի ամենամեծ ֆայլը։ Եթե ցանկանում եք փոխել այն, օրինակի համար, ըստ վերջին փոփոխման ժամանակի, կարող եք դասավորել միայն սխալները արդյունքները ըստ փոփոխման ժամանակի նվազման կարգով, ընտրեք բոլոր կրկնօրինակները, որոնց փոփոխման դելտա ժամանակը բարձր է 0-ից և սեղմեք Դարձնել ընտրվածը հղում։ Պատճառը,որ դասավորում եք ըստ նվազման կարգի այն է, որ եթե 2 ֆայլերից, որոնք կընտրվեն նույն կրկնօրինակ խմբում, երբ սեղմեք Դարձնել ընտրվածը հղում, ապա ցանկի միայն առաջինը կդառնա հղում, մյուսները կանտեսվեն։ Եվ մինչև Դուք ցանկանաք վերջին փոփոխված ֆայլը դարձնել փոփոխված՝ ունենալով դասավորման նվազման կարգը, ապա ցանկի առաջին ֆայլը կլինի վերջին փոփոխված ֆայլը։

+
+

Todo

+

Add "Non-numerical delta" information.

+
+
+
+

Ֆիլտրում

+

dupeGuru-ն աջակցում է հետստուգման ֆիլտրում։ Սրանով Դուք կարող եք սեղմել ներքև արդյունքները, որպեսզի կարողանաք կատարեք գործողություններ դրա հետ։ Օրինակ՝ կարող եք հեշտությամբ նշել բոլոր կրկնօրինակերը նրանց անվան մեջ պարունակող "պատճեն" հատկությամբ՝ ֆիլտրի կողմից օգտագործված արդյունքներից։

+
+

Todo

+

Qt has a toolbar search field now, not a menu item.

+
+

Windows. Ֆիլտրելու հնարավորությունը օգտագործելու համար սեղմեք Գործողություններ --> Կիրառել ֆիլտրը, գրեք կիրառվող ֆիլտրը և սեղմեք Կիրառել։ Չֆիլտրված արդյունքներին վերադառնալու համար սեղմեք Գործողություններ --> Չեղարկել ֆիլտրը։

+

Mac OS X. Ֆիլտրելու հնարավորությունը օգտագործելու համար նշեք Ձեր ֆիլտրը "Ֆիլտր" որոնման դաշտում գործիքաշերտի։ Չֆիլտրված արդյունքներին վերադառնալու համար սեղմեք դատարկ թողեք դաշտը կամ սեղմեք "X"։

+

Պարզ եղանակում (ծրագրային եղանակն է), ինչ տեսակի ֆիլտր է տողում օգտագործվել փաստացի ֆիլտրման համար, խմբային նիշի բացառությամբ *. Այսպիսով, եթե նշում եք "[*]" որպես ֆիլտր, այն կհամընկնի [] փակագծերի հետ, այնուհանդերձ կլինի այդ փակագծերի միջև։

+

Լրացուցիչ ընդլայնված ֆիլտրման համար, կարող եք միացնել "Ֆիլտրելիս օգտագործել կանոնավոր սահմանումները"։ Ապա ֆիլտրման հնարավորությունը կօգտագործվի կանոնավոր սահմանմամբ ։ Կանոնավոր սահմանումը դա համապատասխանացման տեքստի լեզուն է։ Առավել մանրամասն կարող եք կարդալ regular-expressions.info կայքում։

+

Համապատասխանեցումները զգայուն չեն ո՛չ պարզ, ո՛չ էլ regexp եղանակում։

+

Համապատասխանեցման ֆիլտրի դեպքում, Ձեր կանոնավոր սահմանումը չի ունենա ամբողջական ֆայլի անունը, այն միայն կպարունակի սահմանմանը համապատասխան տողին։

+

Կարող եք տեղեկացնել, որ ոչ բոլոր կրկնօրինակներն են ֆիլտրված արդյունքներում համապատասխանում ֆիլտրին։ Ահա թե ինչու ինչքան շուտ որ պարզ կրկնօրինակը խմբում համապատասխանի ֆիլտրին ամբողջ խումբը կմնա արդյունքներում, ուստի ավելի հեշտ կլինի նայելու կրկնօրինակների կազմը։ Այնուհանդերձ, չհամապատասխանող կրկնօրինակերը "հղման եղանակում են"։ Չնայած որ Դուք կարող եք կատարել գործողություններ, ինչպես օրինակ նշել բոլորը և համոզված լինեք, որ միայն նշված են ֆիլտրված կրկնօրինակերը։

+
+
+

Գործողություններ Ընտրացանկը

+
    +
  • Մաքրել անտեսման ցանկը. Հեռացնում է Ձեր ավելացրած բոլոր անտեսված համընկնումները։ Դուք պետք է սկսեք նոր ստուգում, որպեսզի նոր մաքրված անտեսումների ցանկը էֆֆեկտիվ լինի։
  • +
  • Արտածել արդյունքները XHTML-ով. Վերցնում է ընթացիկ արդյունքները և ստեղծում XHTML ֆայլը։ Սյուննրը, որոնք տեսանելի են այս կոճակը սեղմելիս կլինեն նաև XHTML ֆայլում։ Ֆայլը միանգամից կբացվի հիմնական դիտարկիչում։
  • +
  • Ուղարկել նշվածները Աղբարկղ. Բոլոր նշված կրկնօրինակերը հեռացնում է Աղբարկղ։
  • +
  • Ջնջել նշվածը և Վերագրել հղմամբ. Բոլոր նշված կրկնօրինակերը հեռացնում է Աղբարկղ, բայց դա անելուց հետո ջնջված ֆայլերը վերագրվում են ըստ հղման հղվող ֆայլում (Միայն OS X և Linux-ում)
  • +
  • Տեղափոխել նշվածը՝...: Հարցնում է Ձեզ թղթապանակի մասին և ապա տեղափոխում է բոլոր նշված ֆայլերը այդ թղթապանակ։ Աղբյուր ֆայլերի ճանապարհը կարող է վերստեղծվել նշանակության թղթապանակում՝ կախված "Պատճենելու և Տեղափոխելու" կարգավորումներից։
  • +
  • Պատճենել նշվածը՝...: Հարցնում է Ձեզ թղթապանակի մասին և ապա պատճենում է բոլոր նշված ֆայլերը այդ թղթապանակ։ Աղբյուր ֆայլերի ճանապարհը կարող է վերստեղծվել նշանակության թղթապանակում՝ կախված "Պատճենելու և Տեղափոխելու" կարգավորումներից։
  • +
  • Հեռացնել նշվածները արդյունքներից. Հեռացնում է բոլոր նշված կրկնօրինակները արդյունքներից։ Ակտուալ ֆայլերին դա չի վերաբերվի և դրանք կմնան։
  • +
  • Հեռացնել ընտրվածները արդյունքներից. Հեռացնում է բոլոր ընտրված կրկնօրինակները արդյունքներից։ Հիշեք, որ ընտրված բոլոր հղվող ֆայլերը կանտեսվեն,այս գործողությամբ կջնջվեն միայն կրկնօրինակերը։
  • +
  • Դարձնել ընտրվածը հղում. Առաջ է մղում բոլոր ընտրված կրկնօրինակները որպես հղումներ։ Եթե կրկնօրինակը խմբի մասն է, որը ունի հղման թղթապանակ (կապույտ գույնով), ապա ոչ մի գործողություն չի կատարվի դրա համար։ Իսկ եթե միևնույն խմբում կան մեկից ավելի ընտրված կրկնօրինակներ, ապա առաջ կմղվի ամեն խմբից միայն առաջինը։
  • +
  • Ավելացնել ընտրվածը անտեսումների ցանկին. Նախ բոլոր կրկնօրինակները հեռացվում են արդյունքների ցանկից, ապա ավելացվում է կրկնօրինակի համընկումը և ընթացիկ հղումը անտեսումների ցանկին։ Այս համընկնումը այլևս առաջ չի գա հետագա ստուգումների ժամանակ։ Կրկնօրինակը կարող է հետ բերվել, բայց այն կհամապատասխանի հղման այլ ֆայլի։ Կարող եք մաքրել անտեսումների ցանկը Մաքրել անտեսումների ցանկը հրամանով։
  • +
  • Բացել ընտրվածը հիմական ծրագրով. Բացում է ֆայլը իր հետ ասոցիացված ծրագրով։
  • +
  • Ցուցադրել ընտրվածը որոնման մեջ. Բացում է ֆայլը պարունակող թղթապանակը։
  • +
  • Կանչել Ընտրված հրամանը. Բացում է կարգավորումներոմ Ձեր կողմից նշված արտաքին ծրագիրը։
  • +
  • Անվանափոխել ընտրվածը. Ձեզ հարցում կկատարվի նոր անվան համար, ապա ընտրված ֆայլը կանվանափոխվի։
  • +
+
+

Todo

+

Add Move and iPhoto/iTunes warning

+
+
+

Todo

+

Add "Deletion Options" section.

+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/hy/search.html b/help/hy/search.html new file mode 100644 index 00000000..320c1acf --- /dev/null +++ b/help/hy/search.html @@ -0,0 +1,81 @@ + + + + + + + + Search — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + + + + + +
+ + +

Search

+
+ +

+ Please activate JavaScript to enable the search + functionality. +

+
+

+ From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

+
+ + + +
+ +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/help/hy/searchindex.js b/help/hy/searchindex.js new file mode 100644 index 00000000..6febb114 --- /dev/null +++ b/help/hy/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["changelog","faq","folders","index","preferences","quick_start","reprioritize","results"],envversion:53,filenames:["changelog.rst","faq.rst","folders.rst","index.rst","preferences.rst","quick_start.rst","reprioritize.rst","results.rst"],objects:{},objnames:{},objtypes:{},terms:{"32bit":0,"64bit":0,"\u0561\u056f\u057f\u0578\u0582\u0561\u056c":7,"\u0561\u0570\u0561":[4,6,7],"\u0561\u0570\u0574\u0561\u0580":1,"\u0561\u0572\u0562\u0561\u0580\u056f":1,"\u0561\u0572\u0562\u0561\u0580\u056f\u0572":[5,7],"\u0561\u0572\u0562\u0575\u0578\u0582\u0580":[4,7],"\u0561\u0572\u0562\u0575\u0578\u0582\u0580\u056b":4,"\u0561\u0574\u0562\u0578\u0572\u057b":7,"\u0561\u0574\u0562\u0578\u0572\u057b\u0561\u056f\u0561\u0576":7,"\u0561\u0574\u0565\u0576":[4,7],"\u0561\u0574\u0565\u0576\u0561\u0561\u057b":6,"\u0561\u0574\u0565\u0576\u0561\u0574\u0565\u056e":7,"\u0561\u0574\u0565\u0576\u0568":1,"\u0561\u0575\u0564":[1,2,7],"\u0561\u0575\u056c":7,"\u0561\u0575\u056c\u0568\u0576\u057f\u0580\u0561\u0576\u0584\u0575\u056b\u0576":2,"\u0561\u0575\u056c\u0576":6,"\u0561\u0575\u056c\u0587":7,"\u0561\u0575\u056c\u0587\u057d":7,"\u0561\u0575\u0576":[1,3,4,5,6,7],"\u0561\u0575\u0576\u0578\u0582\u0570\u0561\u0576\u0564\u0565\u0580\u0571":[1,3,7],"\u0561\u0575\u0576\u057a\u0565\u057d":1,"\u0561\u0575\u0576\u057f\u0565\u0572":1,"\u0561\u0575\u0578":4,"\u0561\u0575\u057d":[2,3,4,6,7],"\u0561\u0575\u057d\u057a\u056b\u057d\u0578\u057e":[1,7],"\u0561\u0575\u057d\u057f\u0565\u0572":[1,2,4,6,7],"\u0561\u0575\u057d\u057f\u0565\u0572\u056b\u0581":1,"\u0561\u0576\u0563\u0561\u0574":1,"\u0561\u0576\u0564\u0561\u0574":1,"\u0561\u0576\u0565\u056c":7,"\u0561\u0576\u0565\u056c\u0578\u0582":7,"\u0561\u0576\u0565\u056c\u0578\u0582\u0581":7,"\u0561\u0576\u056e\u0561\u0576\u0578\u0569":1,"\u0561\u0576\u0578\u0582\u0576":6,"\u0561\u0576\u0578\u0582\u0576\u0568":[6,7],"\u0561\u0576\u0578\u0582\u0576\u0576\u0565\u0580\u056b":4,"\u0561\u0576\u057e\u0561\u0576":[4,7],"\u0561\u0576\u057e\u0561\u0576\u0561\u0583\u0578\u056d\u0565\u056c":7,"\u0561\u0576\u057e\u0573\u0561\u0580":1,"\u0561\u0576\u057e\u057f\u0561\u0576\u0563\u0578\u0582\u0569\u0575\u0561\u0576":1,"\u0561\u0576\u057f\u0565\u057d\u0565\u056c":4,"\u0561\u0576\u057f\u0565\u057d\u0574\u0561\u0576":7,"\u0561\u0576\u057f\u0565\u057d\u0578\u0582\u0574\u0576\u0565\u0580\u056b":7,"\u0561\u0576\u057f\u0565\u057d\u057e\u0561\u056e":7,"\u0561\u0577\u056d\u0561\u057f\u0561\u0576\u0584\u0568":3,"\u0561\u0577\u056d\u0561\u057f\u0578\u0582\u0574":7,"\u0561\u057a\u0561":[1,2,3,4,5,6,7],"\u0561\u057b":[4,6],"\u0561\u057b\u0561\u056f\u0581\u0578\u0582\u0569\u0575\u0561\u0576":1,"\u0561\u057b\u0561\u056f\u0581\u0578\u0582\u0574":7,"\u0561\u057b\u056b\u0581":6,"\u0561\u057b\u0578\u0582\u0574":6,"\u0561\u057c\u0561\u0576\u0571\u0576\u0561\u0581\u057e\u0578\u0582\u0574":7,"\u0561\u057c\u0561\u0576\u0581":[3,4,7],"\u0561\u057c\u0561\u057b":[1,5,7],"\u0561\u057c\u0561\u057b\u056b\u0576":[2,3,6,7],"\u0561\u057c\u0561\u057b\u056b\u0576\u0568":7,"\u0561\u057c\u0561\u057b\u0576\u0561\u0575\u0576\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0568":7,"\u0561\u057c\u0561\u057e\u0565\u056c":7,"\u0561\u057c\u056f\u0561":4,"\u0561\u057d\u0578\u0581\u056b\u0561\u0581\u057e\u0561\u056e":7,"\u0561\u057d\u057f\u056b\u0573\u0561\u0576":4,"\u0561\u057e\u0561\u0580\u057f\u056b":7,"\u0561\u057e\u0561\u0580\u057f\u057e\u0565\u056c":2,"\u0561\u057e\u0561\u0580\u057f\u057e\u0578\u0582\u0574":6,"\u0561\u057e\u0565\u056c\u0561\u0581\u0576\u0565\u056c":[2,5,7],"\u0561\u057e\u0565\u056c\u0561\u0581\u0576\u0565\u056c\u0578\u057e":6,"\u0561\u057e\u0565\u056c\u0561\u0581\u0576\u0565\u056c\u0578\u0582":[2,6],"\u0561\u057e\u0565\u056c\u0561\u0581\u0576\u0565\u0584":[2,4,7],"\u0561\u057e\u0565\u056c\u0561\u0581\u0576\u0578\u0582\u0574":1,"\u0561\u057e\u0565\u056c\u0561\u0581\u057e\u0561\u056e":2,"\u0561\u057e\u0565\u056c\u0561\u0581\u057e\u0578\u0582\u0574":7,"\u0561\u057e\u0565\u056c\u0561\u0581\u0580\u0561\u056e":7,"\u0561\u057e\u0565\u056c\u0561\u0581\u0580\u0565\u056c":2,"\u0561\u057e\u0565\u056c\u056b":[2,6,7],"\u0561\u057e\u0565\u056c\u056b\u0576":4,"\u0561\u0580\u0561\u0563":3,"\u0561\u0580\u0561\u0563\u0578\u0580\u0565\u0576":7,"\u0561\u0580\u0564\u0565\u0576":[1,4],"\u0561\u0580\u0564\u0575\u0578\u0582\u0576\u0584\u0568":[1,6],"\u0561\u0580\u0564\u0575\u0578\u0582\u0576\u0584\u0576\u0565\u0580":5,"\u0561\u0580\u0564\u0575\u0578\u0582\u0576\u0584\u0576\u0565\u0580\u0568":[3,6],"\u0561\u0580\u0564\u0575\u0578\u0582\u0576\u0584\u0576\u0565\u0580\u056b":[5,7],"\u0561\u0580\u0564\u0575\u0578\u0582\u0576\u0584\u0576\u0565\u0580\u056b\u0576":7,"\u0561\u0580\u0564\u0575\u0578\u0582\u0576\u0584\u0576\u0565\u0580\u056b\u0581":[5,7],"\u0561\u0580\u0564\u0575\u0578\u0582\u0576\u0584\u0576\u0565\u0580\u0578\u0582\u0574":[1,5,7],"\u0561\u0580\u0564\u0575\u0578\u0582\u0576\u0584\u0578\u0582\u0574":1,"\u0561\u0580\u0564\u0575\u0578\u0584":[4,7],"\u0561\u0580\u0565\u0584":7,"\u0561\u0580\u057f\u0561\u056e\u0565\u056c":7,"\u0561\u0580\u057f\u0561\u0584\u056b\u0576":[4,7],"\u0562\u0561\u0566\u0561\u0575\u056b\u0576":5,"\u0562\u0561\u0566\u0574\u0561\u0569\u056b\u057e":5,"\u0562\u0561\u0566\u0574\u0561\u056f\u056b":7,"\u0562\u0561\u056a\u0561\u0576\u057e\u0565\u056c":4,"\u0562\u0561\u056a\u056b\u0576\u0568":6,"\u0562\u0561\u056a\u056b\u0576\u0576":6,"\u0562\u0561\u0575\u0581":[6,7],"\u0562\u0561\u0580\u0571\u0580":7,"\u0562\u0561\u0580\u0571\u0580\u0561\u0563\u0578\u0582\u0575\u0576":6,"\u0562\u0561\u0581\u0561\u057c\u0565\u056c\u0578\u057e":1,"\u0562\u0561\u0581\u0561\u057c\u0578\u0582\u0569\u0575\u0561\u0574\u0562":[4,7],"\u0562\u0561\u0581\u0561\u057c\u057e\u0561\u056e":2,"\u0562\u0561\u0581\u0561\u057f\u0576\u0565\u0580":4,"\u0562\u0561\u0581\u0561\u057f\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0568":4,"\u0562\u0561\u0581\u0561\u0580\u0571\u0561\u056f":[1,7],"\u0562\u0561\u0581\u0565\u056c":[5,7],"\u0562\u0561\u0581\u0565\u056c\u056b\u057d":2,"\u0562\u0561\u0581\u0565\u056c\u0578\u0582":7,"\u0562\u0561\u0581\u0578\u0582\u0574":7,"\u0562\u0561\u0581\u057e\u0578\u0582\u0574":6,"\u0562\u0565\u057c\u0576\u0565\u056c":3,"\u0562\u0565\u0580\u0565\u056c":1,"\u0562\u0565\u0580\u057e\u0565\u056c":7,"\u0562\u0578\u056c\u0578\u0580":[2,4,7],"\u0562\u0578\u056c\u0578\u0580\u0568":[5,7],"\u0562\u0578\u056c\u0578\u0580\u056b":4,"\u0563\u0561":7,"\u0563\u0576\u0561\u0576":6,"\u0563\u0578\u0576\u0565":1,"\u0563\u0578\u0580\u056e\u056b\u0584\u0561\u0577\u0565\u0580\u057f\u056b":7,"\u0563\u0578\u0580\u056e\u056b\u0584\u0576\u0565\u0580":1,"\u0563\u0578\u0580\u056e\u0578\u0572\u0578\u0582\u0569\u0575\u0561\u0574\u0562":[1,4,7],"\u0563\u0578\u0580\u056e\u0578\u0572\u0578\u0582\u0569\u0575\u0561\u0576":6,"\u0563\u0578\u0580\u056e\u0578\u0572\u0578\u0582\u0569\u0575\u0578\u0582\u0576":[4,7],"\u0563\u0578\u0580\u056e\u0578\u0572\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0568":7,"\u0563\u0578\u0580\u056e\u0578\u0572\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0576\u0565\u0580":[1,3,5,6],"\u0563\u0578\u0580\u056e\u0578\u0572\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0576\u0565\u0580\u0568":4,"\u0563\u0578\u0582\u0575\u0576\u0565\u0580\u0578\u057e":7,"\u0563\u0578\u0582\u0575\u0576\u0578\u057e":7,"\u0563\u057f\u0576\u057e\u0561\u056e":2,"\u0563\u057f\u0576\u057e\u0565\u056c":2,"\u0563\u057f\u0576\u057e\u0578\u0582\u0574":6,"\u0563\u0580\u0565\u0584":[1,7],"\u0563\u0581\u0565\u056c\u0568":5,"\u0563\u0581\u0565\u056c\u0578\u057e":2,"\u0563\u0581\u0565\u056c\u0578\u0582":6,"\u0564\u0561":[1,2,6,7],"\u0564\u0561\u0577\u057f\u0568":7,"\u0564\u0561\u0577\u057f\u0578\u0582\u0574":7,"\u0564\u0561\u057d\u0561\u057e\u0578\u0580\u0565\u056c":7,"\u0564\u0561\u057d\u0561\u057e\u0578\u0580\u0565\u056c\u0578\u0582":[1,7],"\u0564\u0561\u057d\u0561\u057e\u0578\u0580\u0574\u0561\u0576":7,"\u0564\u0561\u057d\u0561\u057e\u0578\u0580\u0578\u0582\u0574":7,"\u0564\u0561\u057d\u0561\u057e\u0578\u0580\u0578\u0582\u0574\u0568":6,"\u0564\u0561\u057d\u0561\u057e\u0578\u0580\u057e\u0578\u0582\u0574":7,"\u0564\u0561\u057f\u0561\u0580\u056f":[4,7],"\u0564\u0561\u0580\u0571\u0576\u0565\u056c":[6,7],"\u0564\u0565\u056c\u057f\u0561":[3,6],"\u0564\u0565\u057a\u0584\u0565\u0580\u0578\u0582\u0574":[1,6],"\u0564\u0565\u057a\u0584\u0578\u0582\u0574":[1,4,7],"\u0564\u0565\u057c":1,"\u0564\u056b\u057f\u0561\u0580\u056f\u056b\u0579\u0578\u0582\u0574":7,"\u0564\u056b\u0580\u0584\u0578\u057e":2,"\u0564\u056b\u0580\u0584\u0578\u0582\u0574":6,"\u0564\u0578\u0582\u0580\u057d":4,"\u0564\u0578\u0582\u0584":[1,2,3,4,7],"\u0564\u0580\u0561":[4,7],"\u0564\u0580\u0561\u0576\u0581":7,"\u0564\u0580\u0561\u0576\u0581\u056b\u0581":1,"\u0564\u0580\u0561\u0576\u0584":[2,4,7],"\u0565\u0569\u0565":[1,2,3,4,5,6,7],"\u0565\u056c\u0576\u0565\u056c\u0578\u057e":1,"\u0565\u056f\u0565\u0584":1,"\u0565\u0572\u0561\u0576\u0561\u056f\u0568":[1,7],"\u0565\u0572\u0561\u0576\u0561\u056f\u0576":7,"\u0565\u0572\u0561\u0576\u0561\u056f\u0576\u0565\u0580":5,"\u0565\u0572\u0561\u0576\u0561\u056f\u0576\u0565\u0580\u0568":7,"\u0565\u0572\u0561\u0576\u0561\u056f\u0576\u0565\u0580\u056b\u0581":2,"\u0565\u0572\u0561\u0576\u0561\u056f\u0578\u0582\u0574":[1,7],"\u0565\u0572\u0565\u0584":1,"\u0565\u0576":[1,2,4,5,6,7],"\u0565\u0576\u0569\u0561\u0569\u0572\u0569\u0561\u057a\u0561\u0576\u0561\u056f\u0576\u0565\u0580\u0568":2,"\u0565\u0576\u0569\u0561\u0569\u0572\u0569\u057a\u0561\u0576\u0561\u056f\u0568":2,"\u0565\u0576\u0569\u0561\u0583\u0561\u057d\u057f\u0561\u0580\u056f":6,"\u0565\u0576\u0584":1,"\u0565\u057e":7,"\u0565\u0580\u0562":[2,4,6,7],"\u0565\u0580\u0562\u0565\u0574\u0576":6,"\u0565\u0580\u0562\u0565\u0584":[1,2,7],"\u0565\u0580\u056f\u0578\u0582":6,"\u0565\u0580\u056f\u0578\u0582\u057d\u0576":1,"\u0565\u0580\u056f\u0580\u0578\u0580\u0564":[6,7],"\u0565\u0580\u056f\u0580\u0578\u0580\u0564\u0561\u056f\u0561\u0576":1,"\u0565\u0580\u0587\u0561":2,"\u0565\u0584":[2,3,4,5,6,7],"\u0566\u0563\u0561\u0575\u0578\u0582\u0576":7,"\u0566\u0578\u0570\u056b":4,"\u0567":[2,3,4,5,6,7],"\u0567\u0561\u056f\u0561\u0576":1,"\u0567\u056b\u0576":6,"\u0567\u056c":[1,7],"\u0567\u057b\u056b\u0581":3,"\u0567\u057b\u0578\u0582\u0574":1,"\u0567\u0586\u0586\u0565\u056f\u057f\u056b\u057e":7,"\u0568":[6,7],"\u0568\u0576\u0564\u0563\u056e\u057e\u0578\u0582\u0574":7,"\u0568\u0576\u0564\u056c\u0561\u0575\u0576\u0574\u0561\u0574\u0562":7,"\u0568\u0576\u0564\u056c\u0561\u0575\u0576\u0578\u0582\u0574\u0576\u0565\u0580":4,"\u0568\u0576\u0564\u056c\u0561\u0575\u0576\u057e\u0561\u056e":7,"\u0568\u0576\u0564\u0578\u0582\u0576\u0578\u0582\u0574":7,"\u0568\u0576\u0569\u0561\u0581\u056b\u056f":7,"\u0568\u0576\u056f\u0561\u056c\u0565\u056c\u0578\u0582":3,"\u0568\u0576\u057f\u0580\u0561\u056e":6,"\u0568\u0576\u057f\u0580\u0561\u0576\u0584\u0568":[4,7],"\u0568\u0576\u057f\u0580\u0561\u0576\u0584\u0576\u0565\u0580":6,"\u0568\u0576\u057f\u0580\u0561\u0576\u0584\u0576\u0565\u0580\u056b":6,"\u0568\u0576\u057f\u0580\u0561\u0576\u0584\u0576\u0565\u0580\u0578\u0582\u0574":1,"\u0568\u0576\u057f\u0580\u0561\u0581\u0561\u0576\u056f":2,"\u0568\u0576\u057f\u0580\u0561\u0581\u0561\u0576\u056f\u0568":3,"\u0568\u0576\u057f\u0580\u0561\u0581\u0561\u0576\u056f\u056b\u0576":7,"\u0568\u0576\u057f\u0580\u0561\u0581\u0561\u0576\u056f\u056b\u0581":[4,6],"\u0568\u0576\u057f\u0580\u0565\u056c":[3,7],"\u0568\u0576\u057f\u0580\u0565\u056c\u0578\u0582":[1,6,7],"\u0568\u0576\u057f\u0580\u0565\u0584":[2,4,5,6,7],"\u0568\u0576\u057f\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576":[1,3],"\u0568\u0576\u057f\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0576":2,"\u0568\u0576\u057f\u0580\u0578\u0582\u0574":[3,4],"\u0568\u0576\u057f\u0580\u057e\u0561\u056e":[2,4,5,7],"\u0568\u0576\u057f\u0580\u057e\u0561\u056e\u0568":[5,6,7],"\u0568\u0576\u057f\u0580\u057e\u0561\u056e\u0576\u0565\u0580\u0568":7,"\u0568\u0576\u057f\u0580\u057e\u0578\u0582\u0574":7,"\u0568\u057d\u057f":[1,7],"\u0569\u0561\u0580\u0574\u0561\u0581\u057e\u0561\u056e":3,"\u0569\u0565":[1,4,6,7],"\u0569\u056b\u0574\u056b":1,"\u0569\u056b\u057e\u0568":4,"\u0569\u0572\u0569\u0561\u057a\u0561\u0576\u0561\u056f":[2,4,7],"\u0569\u0572\u0569\u0561\u057a\u0561\u0576\u0561\u056f\u0568":[1,2,4,6,7],"\u0569\u0572\u0569\u0561\u057a\u0561\u0576\u0561\u056f\u056b":[1,3,7],"\u0569\u0572\u0569\u0561\u057a\u0561\u0576\u0561\u056f\u056b\u0581":[2,7],"\u0569\u0572\u0569\u0561\u057a\u0561\u0576\u0561\u056f\u0576\u0565\u0580":[1,2,4,5,7],"\u0569\u0572\u0569\u0561\u057a\u0561\u0576\u0561\u056f\u0576\u0565\u0580\u0568":4,"\u0569\u0572\u0569\u0561\u057a\u0561\u0576\u0561\u056f\u0576\u0565\u0580\u056b":[1,2],"\u0569\u0572\u0569\u0561\u057a\u0561\u0576\u0561\u056f\u0578\u0582\u0574":[2,4,6,7],"\u0569\u0578\u0572\u0565\u0584":7,"\u0569\u057e\u0578\u057e":6,"\u056a\u0561\u0574\u0561\u0576\u0561\u056f":[1,7],"\u056a\u0561\u0574\u0561\u0576\u0561\u056f\u0561\u057e\u0578\u0580":1,"\u056a\u0561\u0574\u0561\u0576\u0561\u056f\u0568":7,"\u056a\u0561\u0574\u0561\u0576\u0561\u056f\u056b":7,"\u056b":7,"\u056b\u0570\u0561\u0580\u056f\u0565":2,"\u056b\u0576":[1,7],"\u056b\u0576\u0579":[1,4,7],"\u056b\u0576\u0579\u0568":1,"\u056b\u0576\u0579\u0576":7,"\u056b\u0576\u0579\u0578\u0582":7,"\u056b\u0576\u0579\u057a\u0565\u057d":[1,4,7],"\u056b\u0576\u0579\u0584\u0561\u0576":7,"\u056b\u0576\u0584\u0576\u0565\u0580\u0564":1,"\u056b\u057d\u056f":7,"\u056b\u057d\u056f\u0561\u056f\u0561\u0576":7,"\u056b\u0580":[4,7],"\u056b\u0580\u0561\u056f\u0561\u0576\u0578\u0582\u0574":[1,5],"\u056b\u0580\u0565\u0576\u0578\u0582\u0574":1,"\u056b\u0580\u0565\u0576\u0581":7,"\u056b\u0580\u0578\u0584\u056b\u0581":7,"\u056b\u0581":7,"\u056c\u0561\u057e":[3,4,6],"\u056c\u0561\u057e\u0561\u0563\u0578\u0582\u0575\u0576":7,"\u056c\u0565\u0566\u0578\u0582\u0576":7,"\u056c\u056b\u0561\u0566\u0578\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0576\u0565\u0580\u0568":1,"\u056c\u056b\u0561\u0566\u0578\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0576\u0565\u0580\u056b":1,"\u056c\u056b\u0561\u0566\u0578\u0580\u0578\u0582\u0574\u0576\u0565\u0580\u0568":1,"\u056c\u056b\u0576\u0565\u056c":[1,2,4],"\u056c\u056b\u0576\u0565\u056c\u0578\u0582":1,"\u056c\u056b\u0576\u0565\u0576":1,"\u056c\u056b\u0576\u0565\u0584":7,"\u056c\u056b\u0576\u056b":[1,4,7],"\u056c\u0580\u0561\u0581\u0578\u0582\u0574\u0576\u0565\u0580":4,"\u056c\u0580\u0561\u0581\u0578\u0582\u0574\u0576\u0565\u0580\u0568":4,"\u056c\u0580\u0561\u0581\u0578\u0582\u0581\u056b\u0579":[1,7],"\u056d\u0565\u056c\u0561\u0574\u056b\u057f":6,"\u056d\u0574\u0562\u0561\u0563\u0580\u0565\u056c":[5,7],"\u056d\u0574\u0562\u0561\u0575\u056b\u0576":7,"\u056d\u0574\u0562\u0565\u0580":1,"\u056d\u0574\u0562\u0565\u0580\u0568":4,"\u056d\u0574\u0562\u0565\u0580\u056b":3,"\u056d\u0574\u0562\u056b":[1,5,6,7],"\u056d\u0574\u0562\u056b\u0581":[2,7],"\u056d\u0574\u0562\u0578\u0582\u0574":[1,2,6,7],"\u056d\u0576\u0564\u056b\u0580\u0576\u0565\u0580":1,"\u056d\u0578\u0580\u0561\u0574\u0561\u0576\u056f\u0578\u0582\u0569\u0575\u0578\u0582\u0576":[1,6],"\u056d\u0578\u0580\u0570\u0578\u0582\u0580\u0564":7,"\u056d\u0578\u0580\u0584\u0561\u0575\u056b\u0576\u056b\u0581":4,"\u056d\u0578\u0582\u0574\u0562":[1,7],"\u056d\u0578\u0582\u0574\u0562\u0568":[6,7],"\u056d\u057d\u057f\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0568":7,"\u056e":7,"\u056e\u0580\u0561\u0563\u056b\u0580":4,"\u056e\u0580\u0561\u0563\u056b\u0580\u0568":7,"\u056e\u0580\u0561\u0563\u0580\u0561\u0575\u056b\u0576":[5,7],"\u056e\u0580\u0561\u0563\u0580\u056b":[1,3],"\u056e\u0580\u0561\u0563\u0580\u0578\u057e":7,"\u056f\u0561":[1,5],"\u056f\u0561\u0566\u0574\u0568":7,"\u056f\u0561\u0566\u0574\u057e\u0561\u056e":7,"\u056f\u0561\u056d\u057e\u0561\u056e":7,"\u056f\u0561\u0574":[1,4,5,6,7],"\u056f\u0561\u0575\u0561\u0576\u0578\u0582\u0574":1,"\u056f\u0561\u0575\u0584\u056b":3,"\u056f\u0561\u0575\u0584\u0578\u0582\u0574":7,"\u056f\u0561\u0576":[1,4,5,7],"\u056f\u0561\u0576\u056d\u0565\u056c\u0578\u0582":7,"\u056f\u0561\u0576\u0578\u0576\u0561\u057e\u0578\u0580":[4,7],"\u056f\u0561\u0576\u0579\u0565\u056c":[4,6,7],"\u056f\u0561\u0576\u057e\u0561\u0576\u0561\u0583\u0578\u056d\u057e\u056b":7,"\u056f\u0561\u0576\u057f\u0565\u057d\u057e\u0565\u0576":7,"\u056f\u0561\u057a\u0576\u057e\u0565\u0584":1,"\u056f\u0561\u057a\u0578\u0582\u0575\u057f":7,"\u056f\u0561\u057a\u057e\u0561\u056e":[1,6],"\u056f\u0561\u057e\u0561\u0580\u057f\u057e\u056b":5,"\u056f\u0561\u057f\u0561\u0580\u0565\u056c":[1,7],"\u056f\u0561\u057f\u0561\u0580\u0565\u056c\u056b":4,"\u056f\u0561\u057f\u0561\u0580\u0565\u056c\u0578\u0582\u0581":7,"\u056f\u0561\u057f\u0561\u0580\u0565\u0584":[5,7],"\u056f\u0561\u057f\u0561\u0580\u057e\u0565\u056c":7,"\u056f\u0561\u057f\u0561\u0580\u057e\u056b":7,"\u056f\u0561\u0580\u0563\u0561\u057e\u0578\u0580\u0574\u0561\u0576":1,"\u056f\u0561\u0580\u0563\u0561\u057e\u0578\u0580\u0578\u0582\u0574\u0568":4,"\u056f\u0561\u0580\u0563\u0561\u057e\u0578\u0580\u0578\u0582\u0574\u0576\u0565\u0580":[3,5],"\u056f\u0561\u0580\u0563\u0561\u057e\u0578\u0580\u0578\u0582\u0574\u0576\u0565\u0580\u0568":5,"\u056f\u0561\u0580\u0563\u0561\u057e\u0578\u0580\u0578\u0582\u0574\u0576\u0565\u0580\u056b":1,"\u056f\u0561\u0580\u0563\u0561\u057e\u0578\u0580\u0578\u0582\u0574\u0576\u0565\u0580\u056b\u0581":7,"\u056f\u0561\u0580\u0563\u0561\u057e\u0578\u0580\u0578\u0582\u0574\u0576\u0565\u0580\u0578\u0574":7,"\u056f\u0561\u0580\u0563\u0568":[1,6,7],"\u056f\u0561\u0580\u0563\u056b":7,"\u056f\u0561\u0580\u0563\u0578\u057e":7,"\u056f\u0561\u0580\u0563\u0578\u0582\u0574":2,"\u056f\u0561\u0580\u0564\u0561\u056c":[1,4,7],"\u056f\u0561\u0580\u0564\u0561\u0581\u0565\u0584":5,"\u056f\u0561\u0580\u0564\u0561\u0584":3,"\u056f\u0561\u0580\u0578\u0572":[2,3,4,6,7],"\u056f\u0561\u0580\u0578\u0572\u0561\u0576\u0561\u0584":7,"\u056f\u0561\u0580\u0578\u0572\u0561\u0576\u0578\u0582\u0574":1,"\u056f\u0561\u0580\u057e\u056b":2,"\u056f\u0561\u0580\u0587\u0578\u0580":6,"\u056f\u0562":7,"\u056f\u0562\u0561\u0581\u057e\u056b":7,"\u056f\u0563\u0561":4,"\u056f\u0563\u0580\u0565\u0584":4,"\u056f\u0564\u0561\u057c\u0576\u0561":7,"\u056f\u0564\u056b\u0574\u056b":4,"\u056f\u0565\u057f\u056b\u0581":6,"\u056f\u0565\u0580\u0587\u0561":2,"\u056f\u0568\u0576\u057f\u0580\u057e\u0565\u0576":7,"\u056f\u0568\u0576\u057f\u0580\u057e\u056b":6,"\u056f\u0569\u0578\u0582\u0575\u056c\u0561\u057f\u0580\u057e\u0565\u0576":4,"\u056f\u056a\u0561\u057c\u0561\u0576\u0563\u0565\u0576":2,"\u056f\u056b\u0580\u0561\u057c\u0565\u056c":7,"\u056f\u056b\u0580\u0561\u057c\u057e\u0578\u0572":7,"\u056f\u056c\u056b\u0576\u0565\u0576":7,"\u056f\u056c\u056b\u0576\u056b":[1,4,6,7],"\u056f\u056f\u0561\u0576\u0579\u057e\u056b":4,"\u056f\u056f\u0561\u057f\u0561\u0580\u057e\u056b":[2,7],"\u056f\u0570\u0561\u0572\u0569\u0565\u0576":6,"\u056f\u0570\u0561\u0574\u0561\u057a\u0561\u057f\u0561\u057d\u056d\u0561\u0576\u056b":7,"\u056f\u0570\u0561\u0574\u0568\u0576\u056f\u0576\u056b":7,"\u056f\u0574\u0572\u057e\u056b":7,"\u056f\u0574\u0576\u0561":7,"\u056f\u0574\u0576\u0561\u0576":7,"\u056f\u0576\u0565\u0580\u0561\u057c\u057e\u0565\u0576":2,"\u056f\u0576\u0577\u057e\u056b":2,"\u056f\u0578\u0572\u0574\u056b\u0581":7,"\u056f\u0578\u0573\u0561\u056f\u0568":[2,5,7],"\u056f\u0578\u0573\u0561\u056f\u056b":6,"\u056f\u0578\u0573\u0561\u056f\u056b\u0576":2,"\u056f\u0578\u0576\u056f\u0580\u0565\u057f":1,"\u056f\u0578\u0576\u0586\u056c\u056b\u056f\u057f\u0568":4,"\u056f\u0578\u0582\u0572\u0561\u0580\u056f\u057e\u0565\u0576":4,"\u056f\u0578\u0582\u0576\u0565\u0576\u0584":1,"\u056f\u057a\u0561\u0570\u057e\u056b":2,"\u056f\u057a\u0561\u0580\u0578\u0582\u0576\u0561\u056f\u0565\u0576":4,"\u056f\u057a\u0561\u0580\u0578\u0582\u0576\u0561\u056f\u056b":7,"\u056f\u057b\u0576\u057b\u0565\u0584":1,"\u056f\u057b\u0576\u057b\u057e\u0565\u0574":2,"\u056f\u057b\u0576\u057b\u057e\u0565\u0576":[4,7],"\u056f\u057d\u057f\u0578\u0582\u0563\u056b":4,"\u056f\u057d\u057f\u0578\u0582\u0563\u057e\u0565\u0576":2,"\u056f\u057e\u0565\u0580\u0561\u0563\u0580\u057e\u0565\u0576":4,"\u056f\u057e\u0565\u0580\u057d\u057f\u0565\u0572\u056e\u057e\u056b":4,"\u056f\u057f\u0565\u0572\u0561\u0564\u0580\u057e\u0565\u0576":7,"\u056f\u0580\u056f\u0576\u0561\u056f\u056b":7,"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f":[1,3,4,5],"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u0565\u056c":5,"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u0565\u056c\u0578\u0582\u0581":5,"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u0565\u0580\u0568":7,"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u0568":[5,7],"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u056b":7,"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u056b\u0576":5,"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u0574\u0561\u0576":7,"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u0576\u0565\u0580":[1,2,3,7],"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u0576\u0565\u0580\u0568":[2,4,6,7],"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u0576\u0565\u0580\u056b":[1,3,4,7],"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u0576\u0565\u0580\u0576":7,"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u057e\u0578\u0572":[1,4,7],"\u056f\u0581\u0561\u0576\u056f\u0561\u0576\u0561\u0584":7,"\u056f\u0581\u0578\u0582\u0581\u0561\u0564\u0580\u056b":7,"\u056f\u0581\u0578\u0582\u0581\u0561\u0564\u0580\u057e\u0565\u0576":7,"\u056f\u0581\u0578\u0582\u0581\u0561\u0564\u0580\u057e\u056b":7,"\u056f\u0583\u0578\u0580\u0571\u0565\u0584":1,"\u056f\u0585\u0563\u0576\u056b":3,"\u056f\u0585\u0563\u057f\u0561\u0563\u0578\u0580\u056e\u057e\u056b":[6,7],"\u0570\u0561\u0572\u0569\u0578\u0572\u056b\u0576":6,"\u0570\u0561\u0573\u0561\u056d":3,"\u0570\u0561\u0574\u0561\u056f\u0561\u0580\u0563":1,"\u0570\u0561\u0574\u0561\u056f\u0561\u0580\u0563\u0561\u0575\u056b\u0576":1,"\u0570\u0561\u0574\u0561\u056f\u0561\u0580\u0563\u0568":1,"\u0570\u0561\u0574\u0561\u0571\u0561\u0575\u0576":7,"\u0570\u0561\u0574\u0561\u057a\u0561\u057f\u0561\u057d\u056d\u0561\u0576":[3,6,7],"\u0570\u0561\u0574\u0561\u057a\u0561\u057f\u0561\u057d\u056d\u0561\u0576\u0561\u0581\u0574\u0561\u0576":7,"\u0570\u0561\u0574\u0561\u057a\u0561\u057f\u0561\u057d\u056d\u0561\u0576\u0565\u0581\u0574\u0561\u0576":7,"\u0570\u0561\u0574\u0561\u057a\u0561\u057f\u0561\u057d\u056d\u0561\u0576\u0565\u0581\u0578\u0582\u0574\u0576\u0565\u0580\u0568":7,"\u0570\u0561\u0574\u0561\u057a\u0561\u057f\u0561\u057d\u056d\u0561\u0576\u056b":7,"\u0570\u0561\u0574\u0561\u057a\u0561\u057f\u0561\u057d\u056d\u0561\u0576\u0578\u0582\u0574":7,"\u0570\u0561\u0574\u0561\u0580":[1,2,3,4,5,6,7],"\u0570\u0561\u0574\u0568\u0576\u056f\u0576\u0578\u0582\u0574":[1,7],"\u0570\u0561\u0574\u0568\u0576\u056f\u0576\u0578\u0582\u0574\u0568":[1,7],"\u0570\u0561\u0574\u0568\u0576\u056f\u0576\u0578\u0582\u0574\u0576\u0565\u0580":1,"\u0570\u0561\u0574\u0568\u0576\u056f\u0576\u0578\u0582\u0574\u0576\u0565\u0580\u0568":[1,7],"\u0570\u0561\u0574\u0568\u0576\u056f\u0578\u0582\u0574\u0568":7,"\u0570\u0561\u0574\u0578\u0566\u0574\u0578\u0582\u0576\u0584":1,"\u0570\u0561\u0574\u0578\u0566\u057e\u0561":7,"\u0570\u0561\u0574\u0578\u0566\u057e\u0561\u056e":[1,2,5,7],"\u0570\u0561\u0575\u057f\u0576\u057e\u0578\u0572":2,"\u0570\u0561\u057b\u0578\u0580\u0564":1,"\u0570\u0561\u057d\u0561\u0576\u0565\u056c\u056b":6,"\u0570\u0561\u057f\u056f\u0578\u0582\u0569\u0575\u0561\u0574\u0562":7,"\u0570\u0561\u057f\u057e\u0561\u056e\u0568":3,"\u0570\u0561\u0580\u0561\u0562\u0565\u0580\u0561\u056f\u0561\u0576":[4,7],"\u0570\u0561\u0580\u0569\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0578\u0582\u0574":4,"\u0570\u0561\u0580\u0569\u0578\u0582\u0574":4,"\u0570\u0561\u0580\u0574\u0561\u0580":7,"\u0570\u0561\u0580\u0574\u0561\u0580\u0565\u0581\u0576\u0565\u056c":1,"\u0570\u0561\u0580\u0581\u0565\u0580":3,"\u0570\u0561\u0580\u0581\u0576\u0578\u0582\u0574":7,"\u0570\u0561\u0580\u0581\u0578\u0582\u0574":[2,7],"\u0570\u0565\u0577\u057f":[1,2,7],"\u0570\u0565\u0577\u057f\u0578\u0582\u0569\u0575\u0561\u0574\u0562":[3,7],"\u0570\u0565\u057c\u0561\u0581\u0576\u0565\u056c":[5,7],"\u0570\u0565\u057c\u0561\u0581\u0576\u0565\u056c\u0578\u0582":2,"\u0570\u0565\u057c\u0561\u0581\u0576\u0578\u0582\u0574":7,"\u0570\u0565\u057c\u0561\u0581\u057e\u0578\u0582\u0574":7,"\u0570\u0565\u057f":[1,7],"\u0570\u0565\u057f\u0561\u0563\u0561":7,"\u0570\u0565\u057f\u0561\u0563\u0561\u0575\u0578\u0582\u0574":1,"\u0570\u0565\u057f\u0578":7,"\u0570\u0565\u057f\u057d\u057f\u0578\u0582\u0563\u0574\u0561\u0576":7,"\u0570\u0565\u057f\u0587\u0575\u0561\u056c":[2,6],"\u0570\u0565\u057f\u0587\u0578\u0582\u0574":6,"\u0570\u0565\u0580\u0569\u056b\u0576":4,"\u0570\u056b\u0574\u0561\u056f\u0561\u0576":7,"\u0570\u056b\u0574\u0576\u0561\u056f\u0561\u0576":[2,7],"\u0570\u056b\u0577\u0565\u0584":7,"\u0570\u0572\u0574\u0561\u0574\u0562":[1,7],"\u0570\u0572\u0574\u0561\u0576":[1,2,4,6,7],"\u0570\u0572\u0574\u0561\u0576\u0568":[5,7],"\u0570\u0572\u0578\u0582\u0574":[2,6,7],"\u0570\u0572\u0578\u0582\u0574\u0568":[4,7],"\u0570\u0572\u0578\u0582\u0574\u0576\u0565\u0580":7,"\u0570\u0572\u0578\u0582\u0574\u0576\u0565\u0580\u0568":[2,4,7],"\u0570\u0572\u0578\u0582\u0574\u0576\u0565\u0580\u056b\u0581":7,"\u0570\u0572\u057e\u0561\u056e":2,"\u0570\u0572\u057e\u0578\u0572":7,"\u0570\u0572\u057e\u0578\u0582\u0574":[4,7],"\u0570\u0576\u0561\u0580\u0561\u057e\u0578\u0580":[1,4],"\u0570\u0576\u0561\u0580\u0561\u057e\u0578\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576":[1,5,6],"\u0570\u0576\u0561\u0580\u0561\u057e\u0578\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0568":[4,7],"\u0570\u0580\u0561\u0574\u0561\u0576\u0568":[4,7],"\u0570\u0580\u0561\u0574\u0561\u0576\u056b":[1,4],"\u0570\u0580\u0561\u0574\u0561\u0576\u0578\u057e":7,"\u0571\u0561\u056d\u0578\u0572\u057e\u056b":1,"\u0571\u0561\u056d\u0578\u0582\u0574":6,"\u0571\u0565\u0566":[1,2,3,6,7],"\u0571\u0565\u057c\u0561\u0564\u056b\u0580":[1,7],"\u0571\u0565\u057c\u0576\u0561\u0580\u056f\u0568":3,"\u0571\u0565\u0580":[2,6,7],"\u0573\u0561\u0576\u0561\u057a\u0561\u0580\u0570\u0568":[4,7],"\u0573\u0561\u0576\u0561\u057a\u0561\u0580\u0570\u056b\u0581":4,"\u0573\u0561\u0576\u0561\u057a\u0561\u0580\u0570\u0576\u0565\u0580\u0568":4,"\u0573\u0561\u0576\u0561\u057a\u0561\u0580\u0570\u0578\u057e":[2,4,7],"\u0573\u056b\u0577\u057f":7,"\u0574\u0561\u056f\u0561\u0580\u0564\u0561\u056f\u0578\u057e":1,"\u0574\u0561\u0576\u0580\u0561\u0574\u0561\u057d\u0576":7,"\u0574\u0561\u0576\u0580\u0561\u0574\u0561\u057d\u0576\u0565\u0580\u0568":7,"\u0574\u0561\u0576\u0580\u0561\u0574\u0561\u057d\u0576\u0565\u0580\u056b":[5,7],"\u0574\u0561\u057d\u056b\u0576":[1,2,3],"\u0574\u0561\u057d\u0576":7,"\u0574\u0561\u057d\u0578\u0582\u0574":6,"\u0574\u0561\u0584\u0580\u0565\u056c":7,"\u0574\u0561\u0584\u0580\u057e\u0561\u056e":7,"\u0574\u0562":7,"\u0574\u0565\u056e":7,"\u0574\u0565\u056e\u0561\u0563\u0578\u0582\u0575\u0576":6,"\u0574\u0565\u056e\u0561\u057a\u0565\u057d":3,"\u0574\u0565\u056f":[1,2,4,7],"\u0574\u0565\u056f\u0568":[1,2,6],"\u0574\u0565\u056f\u056b":2,"\u0574\u0565\u056f\u056b\u0581":7,"\u0574\u0565\u056f\u0578\u0582\u0574":2,"\u0574\u0565\u0576\u0584":1,"\u0574\u0565\u057b":[1,2,7],"\u0574\u056b":[1,2,5,7],"\u0574\u056b\u0561\u056a\u0561\u0574\u0561\u0576\u0561\u056f":1,"\u0574\u056b\u0561\u0575\u0576":[1,2,3,4,5,6],"\u0574\u056b\u0561\u0576\u0563\u0561\u0574\u056b\u0581":[2,7],"\u0574\u056b\u0561\u057d\u056b\u0576":7,"\u0574\u056b\u0561\u0581\u0576\u0565\u056c":[1,7],"\u0574\u056b\u0561\u0581\u0576\u0565\u0584":7,"\u0574\u056b\u0561\u0581\u057e\u0561\u056e":[4,7],"\u0574\u056b\u0574\u0575\u0561\u0576\u0581":[1,7],"\u0574\u056b\u0576\u0579":[2,5],"\u0574\u056b\u0576\u0579\u0587":7,"\u0574\u056b\u0577\u057f":[1,7],"\u0574\u056b\u057b\u0578\u0581\u0578\u057e":6,"\u0574\u056b\u057b\u0587":7,"\u0574\u056b\u057f\u0584":3,"\u0574\u056b\u0587\u0576\u0578\u0582\u0575\u0576":7,"\u0574\u0572\u0578\u0582\u0574":7,"\u0574\u0575\u0578\u0582\u057d\u0576\u0565\u0580\u0568":7,"\u0574\u0576\u0561\u0581\u0561\u056e\u0568":2,"\u0574\u057f\u0561\u056e\u0565\u0576\u0584":1,"\u0575\u0578\u0582\u0580\u0561\u0584\u0561\u0576\u0579\u0575\u0578\u0582\u0580":[2,6],"\u0576":[2,3,4,5,7],"\u0576\u0561\u056d":[1,6,7],"\u0576\u0561\u056d\u0561\u0563\u056e\u057e\u0565\u056c":1,"\u0576\u0561\u056d\u0561\u057a\u0561\u057f\u0580\u0561\u057d\u057f\u0565\u056c\u0578\u057e":4,"\u0576\u0561\u056d\u056f\u056b\u0576\u0578\u0582\u0574":6,"\u0576\u0561\u056d\u0576\u0561\u056f\u0561\u0576":7,"\u0576\u0561\u0575\u0565\u056c":3,"\u0576\u0561\u0575\u0565\u056c\u0576":7,"\u0576\u0561\u0575\u0565\u056c\u0578\u0582":7,"\u0576\u0561\u0575\u0565\u0576\u0584":1,"\u0576\u0561\u0575\u0565\u0584":[2,5],"\u0576\u0561\u0575\u0578\u0582\u0574":3,"\u0576\u0561\u0587":[4,5,7],"\u0576\u0565\u0580\u0561\u057c\u057e\u0561\u056e":1,"\u0576\u0565\u0580\u0584\u0587":7,"\u0576\u0565\u0580\u0584\u0587\u0578\u0582\u0574":7,"\u0576\u056b\u0577\u056b":7,"\u0576\u056e\u0565\u056c":7,"\u0576\u056f\u0561\u057f\u0561\u057c\u0578\u0582\u0574\u0576\u0565\u0580\u056b\u0581":1,"\u0576\u0574\u0561\u0576":1,"\u0576\u0577\u0561\u0576\u0561\u056f\u0578\u0582\u0569\u0575\u0561\u0576":[4,6,7],"\u0576\u0577\u0561\u0576\u0561\u056f\u0578\u0582\u0569\u0575\u0578\u0582\u0576":7,"\u0576\u0577\u0561\u0576\u0561\u056f\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0576\u0565\u0580\u0568":3,"\u0576\u0577\u0561\u0576\u0561\u056f\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0576\u0565\u0580\u056b":7,"\u0576\u0577\u0561\u0576\u0561\u056f\u0578\u0582\u0574":[1,6,7],"\u0576\u0577\u0561\u0576\u0561\u056f\u057e\u0561\u056e":4,"\u0576\u0577\u0561\u0576\u0578\u057e":7,"\u0576\u0577\u0565\u056c":[2,5,7],"\u0576\u0577\u0565\u056c\u0578\u0582":[1,5,7],"\u0576\u0577\u0565\u0584":7,"\u0576\u0577\u0578\u0582\u0574":3,"\u0576\u0577\u057e\u0561\u056e":[4,7],"\u0576\u0577\u057e\u0561\u056e\u0568":[1,5,7],"\u0576\u0577\u057e\u0561\u056e\u0576\u0565\u0580\u0568":7,"\u0576\u0577\u057e\u0565\u056c":5,"\u0576\u0577\u057e\u0578\u0582\u0574":5,"\u0576\u0578\u0580":[2,7],"\u0576\u0578\u0580\u0574\u0561\u056c":[2,7],"\u0576\u0578\u0582\u0575\u0576":[1,4,6,7],"\u0576\u0578\u0582\u0575\u0576\u056b\u0576":4,"\u0576\u0578\u0582\u0575\u0576\u0576":4,"\u0576\u0578\u0582\u0580\u0562":1,"\u0576\u057e\u0561\u0566\u0574\u0561\u0576":7,"\u0576\u0580\u0561":7,"\u0576\u0580\u0561\u0576\u056b\u0581":7,"\u0576\u0580\u0561\u0576\u0581":7,"\u0576\u0580\u0561\u0576\u0581\u056b\u0581":2,"\u0577\u0561\u057f":[1,2,3,4,6,7],"\u0577\u0561\u0580\u0578\u0582\u0576\u0561\u056f\u0578\u0582\u0574":1,"\u0577\u0561\u0580\u0584":1,"\u0577\u0578\u0582\u057f":7,"\u0577\u0580\u057b\u0561\u0576\u0561\u056f\u056b\u0581":4,"\u0577\u0580\u057b\u0561\u0576\u0581\u056b\u056f":1,"\u0578":7,"\u0578\u0579":[1,2,7],"\u0578\u057e":7,"\u0578\u0580":[2,4,5,6,7],"\u0578\u0580\u0568":[1,4,6,7],"\u0578\u0580\u056b":6,"\u0578\u0580\u0578\u0576\u0574\u0561\u0576":7,"\u0578\u0580\u0578\u0576\u0581":7,"\u0578\u0580\u0578\u0576\u0584":[1,2,5,7],"\u0578\u0580\u0578\u0577":[1,7],"\u0578\u0580\u0578\u0577\u0565\u056c":[1,6],"\u0578\u0580\u0578\u0577\u0565\u056c\u0578\u0582":[1,7],"\u0578\u0580\u0578\u0577\u0578\u0582\u0574":[4,7],"\u0578\u0580\u0578\u0577\u057e\u056b":4,"\u0578\u0580\u0578\u057e\u0570\u0565\u057f\u0587":[1,4,7],"\u0578\u0580\u057a\u0565\u057d":[1,2,4,7],"\u0578\u0580\u057a\u0565\u057d\u0566\u056b":7,"\u0578\u0580\u057f\u0565\u0572":[1,4],"\u0578\u0582\u056a\u0568":7,"\u0578\u0582\u0572\u0561\u0580\u056f\u0565\u056c":[5,7],"\u0578\u0582\u0572\u0561\u0580\u056f\u0578\u0582\u0574":1,"\u0578\u0582\u0572\u0572\u0561\u056f\u056b":2,"\u0578\u0582\u0572\u0572\u0565\u056c":4,"\u0578\u0582\u0574":[4,7],"\u0578\u0582\u0576\u0565\u0576":6,"\u0578\u0582\u0576\u0565\u0576\u0561":7,"\u0578\u0582\u0576\u0565\u0576\u0561\u056c\u0578\u057e":7,"\u0578\u0582\u0576\u0565\u0576\u0561\u056c\u0578\u0582":[4,7],"\u0578\u0582\u0576\u0565\u0576\u0584":1,"\u0578\u0582\u0576\u0565\u0584":[4,7],"\u0578\u0582\u0576\u056b":[1,6,7],"\u0578\u0582\u057d\u057f\u056b":[1,7],"\u0579":7,"\u0579\u0561\u056f\u0565\u0580\u057f\u0576\u0565\u0580\u0578\u057e":4,"\u0579\u0561\u0583\u0561\u0566\u0561\u0576\u0581":1,"\u0579\u0561\u0583\u0561\u0576\u056b\u0577\u0576":6,"\u0579\u0561\u0583\u0561\u0576\u056b\u0577\u0576\u0565\u0580":6,"\u0579\u0561\u0583\u0561\u0576\u056b\u0577\u0576\u0565\u0580\u056b":6,"\u0579\u0561\u0583\u0568":[6,7],"\u0579\u0561\u0583\u056b":[6,7],"\u0579\u0561\u0583\u0576":7,"\u0579\u0565\u0572\u0561\u0580\u056f\u0565\u056c":7,"\u0579\u0565\u0576":[1,2,4,7],"\u0579\u0565\u0584":[1,2,7],"\u0579\u0567":[1,5,7],"\u0579\u0568\u0576\u057f\u0580\u0565\u0584":4,"\u0579\u056b":[1,2,5,6,7],"\u0579\u056c\u056b\u0576\u0565\u0576":7,"\u0579\u056f\u0561\u0576":1,"\u0579\u0570\u0561\u0574\u0561\u057a\u0561\u057f\u0561\u057d\u056d\u0561\u0576\u0578\u0572":7,"\u0579\u0576\u0561\u0575\u0561\u056e":[3,7],"\u0579\u057a\u0565\u057f\u0584":1,"\u0579\u057b\u0576\u057b\u0565\u0584":1,"\u0579\u0586\u056b\u056c\u057f\u0580\u057e\u0561\u056e":7,"\u057a\u0561\u0570\u0561\u0576\u057b\u057e\u0578\u0582\u0574":6,"\u057a\u0561\u0570\u0565\u056c":7,"\u057a\u0561\u0570\u0565\u056c\u0578\u0582":3,"\u057a\u0561\u0570\u0565\u0584":[1,7],"\u057a\u0561\u057f\u0573\u0561\u057c\u0568":[1,7],"\u057a\u0561\u057f\u0573\u0561\u057c\u0576":7,"\u057a\u0561\u057f\u0573\u0561\u057c\u0576\u0565\u0580\u0578\u057e":1,"\u057a\u0561\u057f\u0573\u0565\u0576":7,"\u057a\u0561\u057f\u0573\u0565\u0576\u0565\u056c":[4,7],"\u057a\u0561\u057f\u0573\u0565\u0576\u0565\u056c\u0578\u0582":[4,7],"\u057a\u0561\u057f\u0573\u0565\u0576\u0578\u0582\u0574":7,"\u057a\u0561\u057f\u0578\u0582\u0570\u0561\u0576\u0568":[2,6],"\u057a\u0561\u057f\u0578\u0582\u0570\u0561\u0576\u056b":2,"\u057a\u0561\u0580\u0566":7,"\u057a\u0561\u0580\u0566\u0561\u057a\u0565\u057d":[2,5,7],"\u057a\u0561\u0580\u0566\u0578\u0580\u0578\u0577":2,"\u057a\u0561\u0580\u0578\u0582\u0576\u0561\u056f\u0578\u0572":7,"\u057a\u0561\u0580\u0578\u0582\u0576\u0561\u056f\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0568":3,"\u057a\u0561\u0580\u0578\u0582\u0576\u0561\u056f\u0578\u0582\u0574":[2,4],"\u057a\u0565\u057f\u0584":[1,4,6,7],"\u057a\u057f\u057f\u0565\u0584":7,"\u057b\u0576\u057b\u0565\u056c":[4,7],"\u057b\u0576\u057b\u0565\u056c\u0578\u0582":[1,7],"\u057b\u0576\u057b\u0565\u056c\u0578\u0582\u0581":4,"\u057b\u0576\u057b\u0565\u0584":[1,7],"\u057b\u0576\u057b\u056b":1,"\u057b\u0576\u057b\u057e\u0561\u056e":7,"\u057b\u0576\u057b\u057e\u0565\u056c":2,"\u057b\u0576\u057b\u057e\u0565\u056c\u0578\u0582":2,"\u057b\u0576\u057b\u057e\u056b":[2,4],"\u057d\u0561":[4,5,7],"\u057d\u0561\u0570\u0574\u0561\u0576\u0561\u0583\u0561\u056f\u0578\u0582\u0574\u0576\u0565\u0580":1,"\u057d\u0561\u0570\u0574\u0561\u0576\u0574\u0561\u0574\u0562":7,"\u057d\u0561\u0570\u0574\u0561\u0576\u0574\u0561\u0576\u0568":7,"\u057d\u0561\u0570\u0574\u0561\u0576\u0578\u0582\u0574":4,"\u057d\u0561\u0570\u0574\u0561\u0576\u0578\u0582\u0574\u0568":7,"\u057d\u0561\u0570\u0574\u0561\u0576\u0578\u0582\u0574\u0576\u0565\u0580":4,"\u057d\u0561\u0570\u0574\u0561\u0576\u0578\u0582\u0574\u0576\u0565\u0580\u0568":7,"\u057d\u0565\u0572\u0574\u0561\u056e":7,"\u057d\u0565\u0572\u0574\u0561\u0574\u0562":7,"\u057d\u0565\u0572\u0574\u0565\u056c":[2,7],"\u057d\u0565\u0572\u0574\u0565\u056c\u056b\u057d":[2,7],"\u057d\u0565\u0572\u0574\u0565\u056c\u0578\u057e":7,"\u057d\u0565\u0572\u0574\u0565\u0584":[1,2,5,6,7],"\u057d\u0565\u0572\u0574\u0578\u0582\u0574":2,"\u057d\u056c\u0561\u0584\u056b":6,"\u057d\u056d\u0561\u056c":[5,6,7],"\u057d\u056d\u0561\u056c\u0568":6,"\u057d\u056d\u0561\u056c\u056b":6,"\u057d\u056d\u0561\u056c\u056b\u0576":6,"\u057d\u056d\u0561\u056c\u0576\u0565\u0580\u0568":[1,3,6],"\u057d\u056f\u056b\u0566\u0562":3,"\u057d\u056f\u057d\u0565\u056c\u0578\u0582":5,"\u057d\u056f\u057d\u0565\u0584":7,"\u057d\u0575\u0561\u0576\u0568":[1,7],"\u057d\u0575\u0578\u0582\u0576\u0565\u0580":7,"\u057d\u0575\u0578\u0582\u0576\u0568":7,"\u057d\u0575\u0578\u0582\u0576\u056b\u0581":7,"\u057d\u0575\u0578\u0582\u0576\u0576\u0580\u0568":7,"\u057d\u0575\u0578\u0582\u0576\u0578\u0582\u0574":7,"\u057d\u057a\u0561\u057d\u0565\u0584":5,"\u057d\u057f\u0561\u0576\u0561\u056c\u0578\u0582":1,"\u057d\u057f\u0561\u0576\u0564\u0561\u0580\u057f":[5,7],"\u057d\u057f\u0561\u0576\u0578\u0582\u0574":6,"\u057d\u057f\u0565\u0572\u056e\u0565\u056c":1,"\u057d\u057f\u0565\u0572\u056e\u0578\u0582\u0574":[1,7],"\u057d\u057f\u0578\u0582\u0563\u0565\u056c":[2,5],"\u057d\u057f\u0578\u0582\u0563\u0565\u056c\u0578\u0582":[1,5],"\u057d\u057f\u0578\u0582\u0563\u056b\u0579\u0568":1,"\u057d\u057f\u0578\u0582\u0563\u0574\u0561\u0576":[2,3],"\u057d\u057f\u0578\u0582\u0563\u0578\u0582\u0574":[1,5,7],"\u057d\u057f\u0578\u0582\u0563\u0578\u0582\u0574\u0568":[1,5,7],"\u057d\u057f\u0578\u0582\u0563\u0578\u0582\u0574\u0576\u0565\u0580\u056b":7,"\u057d\u057f\u0578\u0582\u0563\u057e\u0565\u056c":5,"\u057d\u0580\u0561":1,"\u057d\u0580\u0561\u0576":1,"\u057d\u0580\u0561\u0576\u0578\u057e":7,"\u057e\u0561\u0570\u0561\u0576\u0561\u056f":4,"\u057e\u0561\u0570\u0561\u0576\u0561\u056f\u0568":7,"\u057e\u0561\u0570\u0561\u0576\u0561\u056f\u056b\u0581":4,"\u057e\u0561\u0576\u0564\u0561\u056f\u0568":4,"\u057e\u0565\u0562":3,"\u057e\u0565\u0580":4,"\u057e\u0565\u0580\u0561\u0561\u057c\u0561\u057b\u0576\u0561\u0575\u0576\u0561\u057e\u0578\u0580\u0574\u0561\u0576":6,"\u057e\u0565\u0580\u0561\u0561\u057c\u0561\u057b\u0576\u0561\u0575\u0576\u0578\u0582\u0569\u0575\u0561\u0576":3,"\u057e\u0565\u0580\u0561\u0562\u0565\u0580\u057e\u056b":7,"\u057e\u0565\u0580\u0561\u0563\u0580\u0565\u056c":7,"\u057e\u0565\u0580\u0561\u0563\u0580\u057e\u0578\u0582\u0574":7,"\u057e\u0565\u0580\u0561\u0564\u0561\u057c\u0576\u0561\u056c\u0578\u0582":7,"\u057e\u0565\u0580\u0561\u056f\u0561\u0580\u0563\u0561\u057e\u0578\u0580\u0565\u056c":6,"\u057e\u0565\u0580\u057b\u056b\u0576":[2,7],"\u057e\u0565\u0580\u057b\u0576\u0561\u056f\u0561\u0576":[1,4],"\u057e\u0565\u0580\u057d\u056f\u057d\u0565\u0584":1,"\u057e\u0565\u0580\u057d\u057f\u0565\u0572\u056e\u0565\u056c":4,"\u057e\u0565\u0580\u057d\u057f\u0565\u0572\u056e\u0565\u056c\u0578\u0582":4,"\u057e\u0565\u0580\u057d\u057f\u0565\u0572\u056e\u057e\u0565\u056c":7,"\u057e\u0565\u0580\u0581\u0576\u0565\u056c":[5,6],"\u057e\u0565\u0580\u0581\u0576\u0578\u0582\u0574":7,"\u057e\u056b\u0573\u0561\u056f\u0568":[3,7],"\u057e\u056b\u0573\u0561\u056f\u0578\u0582\u0574":7,"\u057e\u0580\u0561":[1,2,7],"\u057f\u0561":1,"\u057f\u0561\u056c\u056b\u057d":[1,5,6],"\u057f\u0561\u0580\u0562\u0565\u0580":[4,5,7],"\u057f\u0561\u0580\u0562\u0565\u0580\u0561\u056f\u0578\u0582\u0574":1,"\u057f\u0565\u0572":4,"\u057f\u0565\u0572\u0561\u0564\u0580\u0565\u056c":7,"\u057f\u0565\u0572\u0561\u0564\u0580\u0565\u056c\u0578\u0582":7,"\u057f\u0565\u0572\u0561\u0564\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u056b\u0581":4,"\u057f\u0565\u0572\u0561\u0564\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0578\u0582\u0574":4,"\u057f\u0565\u0572\u0561\u057e\u0578\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0568":4,"\u057f\u0565\u0572\u0561\u0583\u0578\u056d\u0565\u056c":[1,4,7],"\u057f\u0565\u0572\u0561\u0583\u0578\u056d\u0565\u056c\u056b\u057d":1,"\u057f\u0565\u0572\u0561\u0583\u0578\u056d\u0565\u056c\u0578\u0582":[4,7],"\u057f\u0565\u0572\u0561\u0583\u0578\u056d\u0565\u056c\u0578\u0582\u0581":4,"\u057f\u0565\u0572\u0561\u0583\u0578\u056d\u0565\u0584":4,"\u057f\u0565\u0572\u0561\u0583\u0578\u056d\u0578\u0582\u0574":7,"\u057f\u0565\u0572\u0561\u0583\u0578\u056d\u057e\u056b":4,"\u057f\u0565\u0572\u0565\u056f\u0561\u0581\u0576\u0565\u056c":7,"\u057f\u0565\u0572\u0565\u056f\u0561\u0581\u0578\u0582\u0574":1,"\u057f\u0565\u0572\u0578\u0580\u0578\u0577\u0578\u0582\u0574\u0568":6,"\u057f\u0565\u0572\u0578\u0582\u0574":4,"\u057f\u0565\u057d\u0561\u056f\u0568":[4,7],"\u057f\u0565\u057d\u0561\u056f\u056b":7,"\u057f\u0565\u057d\u0561\u0576\u0565\u056c\u056b":7,"\u057f\u0565\u057d\u0576\u0565\u056c":7,"\u057f\u0565\u057d\u0576\u0565\u056c\u0578\u0582":4,"\u057f\u0565\u057d\u0576\u0578\u0582\u0574":2,"\u057f\u0565\u0584\u057d\u057f\u056b":7,"\u057f\u0578\u0572\u0568":1,"\u057f\u0578\u0572\u056b\u0576":7,"\u057f\u0578\u0572\u0578\u0582\u0574":[4,7],"\u057f\u057e\u0565\u056c":1,"\u057f\u057e\u0575\u0561\u056c\u0576\u0565\u0580\u056b":4,"\u057f\u0580\u057e\u0561\u056e":2,"\u057f\u0580\u057e\u0578\u0572":3,"\u057f\u0580\u057e\u0578\u0582\u0574":7,"\u0581\u0561\u056e\u0580":[1,7],"\u0581\u0561\u0576\u056f\u0561\u0576\u0561\u0584":7,"\u0581\u0561\u0576\u056f\u0561\u0576\u0578\u0582\u0574":[2,7],"\u0581\u0561\u0576\u056f\u0561\u0581\u0561\u056e":[4,5],"\u0581\u0561\u0576\u056f\u0568":[2,6,7],"\u0581\u0561\u0576\u056f\u056b":[6,7],"\u0581\u0561\u0576\u056f\u056b\u0576":7,"\u0581\u0561\u0576\u056f\u056b\u0581":7,"\u0581\u0561\u0576\u056f\u0578\u0582\u0574":[2,6,7],"\u0581\u0578\u0582\u0581\u0561\u0564\u0580\u0565\u056c":3,"\u0581\u0578\u0582\u0581\u0561\u0564\u0580\u0578\u0582\u0574":7,"\u0581\u0578\u0582\u0581\u0561\u0564\u0580\u057e\u0578\u0582\u0574":7,"\u0583\u0561\u056f\u0561\u0563\u056e\u0565\u0580\u056b":7,"\u0583\u0561\u056f\u0565\u0584":4,"\u0583\u0561\u057d\u057f\u0561\u0569\u0572\u0569\u056b":4,"\u0583\u0561\u057d\u057f\u0561\u0580\u056f":6,"\u0583\u0561\u057d\u057f\u0561\u0580\u056f\u0568":6,"\u0583\u0561\u057d\u057f\u0561\u0580\u056f\u056b":6,"\u0583\u0561\u057d\u057f\u0561\u0580\u056f\u056b\u0576":6,"\u0583\u0561\u057d\u057f\u0561\u0580\u056f\u0576":6,"\u0583\u0561\u057d\u057f\u0561\u0580\u056f\u0576\u0565\u0580\u0568":6,"\u0583\u0561\u057d\u057f\u0561\u0581\u056b":7,"\u0583\u0578\u056d\u0561\u0576\u0581\u0574\u0561\u0576":4,"\u0583\u0578\u056d\u0561\u0580\u0565\u0576":[2,7],"\u0583\u0578\u056d\u0561\u0580\u0565\u0576\u0568":4,"\u0583\u0578\u056d\u0565\u056c":7,"\u0583\u0578\u056d\u0565\u056c\u0578\u0582":7,"\u0583\u0578\u0580\u0571\u0565\u056c\u0578\u0582":4,"\u0583\u0578\u0580\u0571\u0576\u0561\u056f\u0561\u0576":1,"\u0583\u0578\u0580\u0571\u0578\u0582\u0574":6,"\u0583\u0578\u0583\u0578\u056d\u0565\u056c":7,"\u0583\u0578\u0583\u0578\u056d\u0574\u0561\u0576":[5,7],"\u0583\u0578\u0583\u0578\u056d\u057e\u0561\u056e":7,"\u0584\u0561\u0576":7,"\u0584\u0561\u0576\u056b":[5,7],"\u0585\u0563\u0576\u0565\u056c":1,"\u0585\u0563\u0576\u0565\u056c\u0578\u0582":7,"\u0585\u0563\u0576\u0578\u0582\u0569\u0575\u0561\u0576":[3,5],"\u0585\u0563\u057f\u0561\u0563\u0578\u0580\u056e\u0565\u056c":[1,2,4,7],"\u0585\u0563\u057f\u0561\u0563\u0578\u0580\u056e\u0565\u056c\u0578\u057e":[1,5],"\u0585\u0563\u057f\u0561\u0563\u0578\u0580\u056e\u0565\u056c\u0578\u0582":7,"\u0585\u0563\u057f\u0561\u0563\u0578\u0580\u056e\u0578\u0582\u0574":7,"\u0585\u0563\u057f\u0561\u0563\u0578\u0580\u056e\u057e\u0561\u056e":7,"\u0585\u0563\u057f\u0561\u0563\u0578\u0580\u056e\u057e\u0565\u056c":[3,7],"\u0585\u0563\u057f\u0561\u0563\u0578\u0580\u056e\u057e\u056b":6,"\u0585\u0563\u057f\u0561\u0563\u0578\u0580\u056e\u057e\u0578\u0582\u0574":6,"\u0585\u0563\u057f\u0561\u056f\u0561\u0580":4,"\u0585\u0578\u0580":7,"\u0585\u0580\u056b\u0576\u0561\u056f":[1,4,6,7],"\u0585\u0580\u056b\u0576\u0561\u056f\u056b":[1,7],"\u0586\u0561\u0575\u056c":[1,2],"\u0586\u0561\u0575\u056c\u0565\u0580":[5,6,7],"\u0586\u0561\u0575\u056c\u0565\u0580\u0568":[2,4,6,7],"\u0586\u0561\u0575\u056c\u0565\u0580\u056b":7,"\u0586\u0561\u0575\u056c\u0565\u0580\u056b\u0576":7,"\u0586\u0561\u0575\u056c\u0565\u0580\u056b\u0581":7,"\u0586\u0561\u0575\u056c\u0565\u0580\u0576":1,"\u0586\u0561\u0575\u056c\u0565\u0580\u0578\u0582\u0574":1,"\u0586\u0561\u0575\u056c\u0568":[3,4,5,6,7],"\u0586\u0561\u0575\u056c\u056b":[1,4,6,7],"\u0586\u0561\u0575\u056c\u056b\u0576":[2,4],"\u0586\u0561\u0575\u056c\u056b\u0581":2,"\u0586\u0561\u0575\u056c\u0576":7,"\u0586\u0561\u0575\u056c\u0578\u057e":4,"\u0586\u0561\u0575\u056c\u0578\u0582\u0574":7,"\u0586\u056b\u056c\u057f\u0580":7,"\u0586\u056b\u056c\u057f\u0580\u0565\u056c\u056b\u057d":[4,7],"\u0586\u056b\u056c\u057f\u0580\u0565\u056c\u0578\u0582":7,"\u0586\u056b\u056c\u057f\u0580\u0568":7,"\u0586\u056b\u056c\u057f\u0580\u056b":[1,7],"\u0586\u056b\u056c\u057f\u0580\u056b\u0576":7,"\u0586\u056b\u056c\u057f\u0580\u0574\u0561\u0576":[4,7],"\u0586\u056b\u056c\u057f\u0580\u0578\u0582\u0574":3,"\u0586\u056b\u056c\u057f\u0580\u057e\u0561\u056e":7,"\u0587":[1,2,3,4,5,6],"ale\u0161":0,"byte":0,"case":0,"default":0,"export":0,"import":0,"long":0,"new":0,"switch":0,"t\u00e4tzner":0,"try":0,"while":0,Added:0,But:0,The:0,These:0,Was:0,abil:0,about:0,accident:0,action:0,activ:0,add:[0,2,7],added:0,adding:0,affect:0,after:0,again:0,alarm:0,algorithm:0,all:0,allow:0,alreadi:0,also:0,analyz:0,anh:0,annoy:0,anymor:0,anywai:0,apertur:[0,2],app:0,appli:0,applic:0,arbitrari:0,arch:0,archive2015:0,aren:0,armenian:0,ascii:0,ask:0,attribut:0,attributeerror:0,audio:0,auto:0,automat:0,avoid:0,awar:0,back:0,backend:0,bad:0,bar:[0,6],base:0,batchmod:1,becam:0,been:0,begin:0,behavior:0,being:0,between:0,big:0,bin:0,bind:0,bit:0,block:0,blue:0,brazilian:0,bring:0,broken:0,bsd:0,bug:0,build:0,bump:0,bundl:0,button:0,cach:0,call:0,came:0,can:0,cancel:0,caus:0,ceil:0,cell:0,certain:0,chang:0,changelog:3,charact:0,chines:0,choos:0,chosen:0,clear:0,clearer:0,click:0,cmd:0,cocoa:0,collect:0,color:0,column:0,comboboxmodel:0,come:0,command:[0,7],comparison:0,compat:0,complement:0,complet:0,configur:0,confus:0,contain:0,content:0,context:0,control:7,convers:0,convert:0,copi:0,core:0,correct:0,correctli:0,corrupt:0,couldn:0,count:0,coupl:0,crash:0,creat:0,creation:0,criteria:0,csv:0,custom:0,czech:0,date:0,debug:0,dee:0,delet:[0,7],delta:[0,7],depend:0,descriptor:0,design:0,destin:0,detail:0,detect:0,detinov:0,dialog:0,directori:0,disabl:0,discard:0,displai:0,document:0,doe:0,don:0,doubl:0,drag:0,dramat:0,drop:0,due:0,dupe:0,dupeguru:[0,2,4,5,6,7],duplic:0,dure:0,dutch:0,each:0,edit:0,effici:0,elegantli:0,empti:0,enabl:0,end:0,engin:0,english:1,eric:0,error:0,especi:0,even:0,exact:0,exclud:0,exclus:0,exe:[4,7],exist:0,express:[0,4,7],ext:4,extens:0,fact:0,fairwar:0,fals:0,faq:1,featur:0,feedback:0,fetch:0,few:0,field:[0,7],figueiredo:0,file:[0,4],filenam:0,filter:0,find:0,finder:0,fix:0,focu:0,folder:0,font:0,foo:6,foobar:4,format:0,found:0,frank:0,freez:0,french:0,from:0,fuzzi:0,gabriel:0,german:0,get:0,ghost:0,github:0,glitch:0,going:0,gplv3:0,greatli:0,greek:0,gregor:0,group:0,gui:0,had:0,handl:0,happen:0,hard:0,hardcod:0,hardlink:0,has:[0,7],have:0,help:0,here:0,homepag:3,hour:0,how:0,hrant:0,html:0,http:0,icon:0,ignor:0,igor:0,improv:0,inaccuraci:0,inconveni:0,index:3,info:[0,4,7],inform:7,initi:0,inod:4,insensit:0,instead:0,interfac:0,intern:0,internation:0,introduc:0,invoc:0,involv:0,iphoto:[0,2,7],issu:0,italian:0,item:[0,7],itun:[0,2,7],job:0,jumpi:0,just:0,keep:0,keybind:0,kind:0,korean:0,koutilelli:0,kyril:0,larg:0,last:0,latin:0,launch:0,length:0,librari:2,licens:0,like:0,limit:0,linux:[0,4,7],lion:0,list:0,littl:0,load:0,local:0,localis:0,locat:0,longer:0,longest:0,lose:0,lost:0,lot:0,low:0,mac:[0,7],machin:0,maco:0,made:0,main:0,make:0,mani:0,mark:0,marker:0,mass:0,match:0,mayb:0,mean:0,media:0,memori:0,menu:[0,7],merg:0,messag:0,might:0,min:0,minimum:0,minor:0,mishandl:0,mistakenli:0,mode:[0,1],more:0,mostli:0,move:[0,7],mp3:0,much:0,multipl:0,music:0,mydestin:4,nah:0,name:0,nasti:0,nehyba:0,net:0,non:[0,7],note:2,noth:0,notic:0,now:[0,7],number:0,numer:[0,7],object:0,obsolet:0,occasion:0,occur:0,ohanyan:0,onc:0,one:0,onli:0,open:0,oper:0,option:[0,7],order:0,outdat:1,overwrit:0,packag:0,page:3,panel:0,paolo:0,part:0,path:0,pavlov:0,permiss:0,permissionerror:0,petrashko:0,phan:0,phase:0,pictur:0,place:0,polish:0,pop:0,posit:0,possibl:0,post:0,power:0,predict:0,pref:0,prefer:0,present:0,pretti:0,prevent:0,previou:0,priorit:0,problem:0,process:0,program:4,progress:0,propag:0,put:0,pyqt:0,python:0,qestion:1,quicklook:0,quit:0,random:0,read:0,realli:0,recent:0,recycl:0,reduc:0,ref:0,refactor:0,refer:0,refresh:0,regexp:7,registr:0,regular:[0,4,7],relat:0,releas:0,relev:0,reliabl:0,reload:0,rememb:0,remind:0,remov:0,renam:0,replac:0,report:0,requir:0,reset:0,respons:0,restor:0,result:0,revamp:0,reveal:0,rewrit:0,right:0,roman:0,rossi:0,round:0,run:0,russian:0,same:0,save:0,scan:0,scanner:0,screen:0,search:[3,7],section:7,see:1,seek:0,seldom:0,select:0,send:0,sensibl:0,sent:0,separ:0,set:0,shelv:0,shift:7,shortest:0,show:0,side:0,sierra:0,significantli:0,similar:0,simpli:0,simplifi:0,sinc:0,situat:0,size:0,small:0,smartli:0,soft:0,softwar:0,some:0,somefil:4,somefold:4,sometim:0,sort:0,space:[1,7],spanish:0,sparkl:0,speed:0,sphinx:0,stall:0,standard:0,start:0,startup:0,state:0,statu:0,sticki:0,stop:0,stuck:0,subfold:[0,4],subsequ:0,superdiffprog:4,support:0,sure:0,surrog:0,symlink:0,sync:0,system:0,systemat:0,tabl:0,technic:0,tell:0,temporarili:0,text:0,than:0,them:0,therefor:0,thi:[0,1],thread:0,threshold:0,through:0,tiger:0,too:0,toolbar:7,trash:0,tweak:0,type:0,typo:0,ubuntu:0,ukrainian:0,under:0,unicod:0,unicodeencodeerror:0,univers:0,unmaintain:0,unpaid:0,unsav:0,updat:0,upgrad:0,upon:0,usag:0,use_regexp:0,used:0,useful:0,user:[0,4],using:0,valu:0,variou:0,veri:0,version:[0,1],victor:0,vietnames:0,vista:0,visual:0,wai:0,want:0,warn:[0,7],wasn:0,weber:0,weight:0,well:0,were:0,when:0,where:0,which:0,whole:0,window:[0,7],woe:0,wonder:0,word:0,work:0,would:0,wouldn:0,writabl:0,wrong:0,www:0,xhtml:[0,7],yeah:0,you:0,your:0,yuri:0},titles:["Changelog","\u0540\u0561\u0573\u0561\u056d \u054f\u0580\u057e\u0578\u0572 \u0540\u0561\u0580\u0581\u0565\u0580","\u0539\u0572\u0569\u0561\u057a\u0561\u0576\u0561\u056f\u056b \u0568\u0576\u057f\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576","dupeGuru help","\u053f\u0561\u0580\u0563\u0561\u057e\u0578\u0580\u0578\u0582\u0574\u0576\u0565\u0580","\u0531\u0580\u0561\u0563 \u054d\u056f\u056b\u0566\u0562","\u054e\u0565\u0580\u0561\u0561\u057c\u0561\u057b\u0576\u0561\u0575\u0576\u0578\u0582\u0569\u0575\u0561\u0576 \u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u0576\u0565\u0580","\u0531\u0580\u0564\u0575\u0578\u0582\u0576\u0584\u0576\u0565\u0580\u0568"],titleterms:{"\u0561\u0572\u0562\u0561\u0580\u056f\u0572":1,"\u0561\u0575\u057d":1,"\u0561\u0576\u0565\u056c":1,"\u0561\u0576\u057e\u057f\u0561\u0576\u0563":1,"\u0561\u057c\u0561\u0576\u0571\u0576\u0561\u0581\u0576\u0578\u0582\u0574":1,"\u0561\u057d\u0578\u0582\u0574":1,"\u0561\u0580\u0561\u0563":5,"\u0561\u0580\u0564\u0575\u0578\u0582\u0576\u0584\u0576\u0565\u0580\u0568":7,"\u0562\u0561\u0575\u0581":1,"\u0562\u0578\u056c\u0578\u0580":1,"\u0563\u0578\u0580\u056e\u0578\u0572\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0576\u0565\u0580":7,"\u0564\u0565\u056c\u057f\u0561":7,"\u0564\u0580\u0578\u0582\u0569\u0575\u0561\u0576":1,"\u0565\u0574":1,"\u0565\u057d":1,"\u0565\u0584":1,"\u0567":1,"\u0568":1,"\u0568\u0576\u057f\u0580\u0561\u0581\u0561\u0576\u056f\u0568":7,"\u0568\u0576\u057f\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576":2,"\u0568\u0576\u057f\u0580\u0578\u0582\u0574":7,"\u0569\u0572\u0569\u0561\u057a\u0561\u0576\u0561\u056f":1,"\u0569\u0572\u0569\u0561\u057a\u0561\u0576\u0561\u056f\u056b":2,"\u0569\u0572\u0569\u0561\u057a\u0561\u0576\u0561\u056f\u056b\u0581":1,"\u056b":1,"\u056b\u0576\u0571":1,"\u056b\u0576\u0579\u0578\u0582":1,"\u056b\u0580\u0561\u057a\u0565\u057d":1,"\u056c\u056b\u0581\u0565\u0576\u0566\u056b\u0561\u0575\u056b":1,"\u056d\u0574\u0562\u0565\u0580\u056b":7,"\u056e\u0580\u0561\u0563\u056b\u0580\u0568":1,"\u056e\u0580\u0561\u0563\u0580\u0565\u0580\u056b\u0581":1,"\u056f\u0561\u0580\u0563\u0561\u057e\u0578\u0580\u0578\u0582\u0574\u0576\u0565\u0580":4,"\u056f\u0561\u0580\u0578\u0572":1,"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f":7,"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u0576\u0565\u0580":6,"\u056f\u0580\u056f\u0576\u0585\u0580\u056b\u0576\u0561\u056f\u0576\u0565\u0580\u0568":1,"\u0570\u0561\u0573\u0561\u056d":1,"\u0570\u0561\u0580\u0581\u0565\u0580":1,"\u0574\u0561\u057d\u056b\u0576":7,"\u0574\u056b\u0561\u0575\u0576":7,"\u0574\u0575\u0578\u0582\u057d":1,"\u0576":1,"\u0576\u0561\u0575\u0565\u056c":7,"\u0576\u0574\u0561\u0576\u0561\u057f\u056b\u057a":1,"\u0576\u0577\u0561\u0576\u0561\u056f\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0576\u0565\u0580\u0568":7,"\u0576\u0577\u0565\u056c":1,"\u0576\u0577\u0578\u0582\u0574":7,"\u0576\u0577\u057e\u0561\u056e":1,"\u0576\u0579":1,"\u0576\u0579\u0576":1,"\u0578":1,"\u0578\u0580":1,"\u0578\u0580\u0578\u0577\u057e\u0561\u056e":1,"\u0578\u0580\u057f\u0565\u0572\u056b\u0581":1,"\u0578\u0582\u0572\u0561\u0580\u056f\u0565\u056c":1,"\u0578\u0582\u0576\u0565\u0574":1,"\u0579\u0565\u0574":1,"\u0579\u0565\u057d":1,"\u057b\u0576\u057b\u0565\u056c":1,"\u057d\u0561":1,"\u057d\u0561\u0570\u0574\u0561\u0576\u0561\u0583\u0561\u056f\u0578\u0582\u0574\u0576\u0565\u0580\u0568":1,"\u057d\u056d\u0561\u056c\u0576\u0565\u0580\u0568":7,"\u057d\u056f\u056b\u0566\u0562":5,"\u057e\u0565\u0580\u0561\u0561\u057c\u0561\u057b\u0576\u0561\u0575\u0576\u0578\u0582\u0569\u0575\u0561\u0576":6,"\u057e\u056b\u0573\u0561\u056f\u0568":2,"\u057e\u0576\u0561\u057d\u057e\u0561\u056e":1,"\u057f\u0578\u0572\u0578\u0582\u0574":1,"\u057f\u0580\u057e\u0578\u0572":1,"\u0580\u0578\u0576":1,"\u0580\u0584\u0561\u0576\u0578\u057e":1,"\u0581\u0561\u0576\u056f\u0561\u0576\u0578\u0582\u0574":1,"\u0581\u0578\u0582\u0581\u0561\u0564\u0580\u0565\u056c":7,"\u0583\u0578\u0580\u0571\u0578\u0582\u0574":1,"\u0585\u0563\u057f\u0561\u0563\u0578\u0580\u056e\u0565\u056c\u0578\u0582":1,"\u0586\u0561\u0575\u056c\u0565\u0580":1,"\u0586\u0561\u0575\u056c\u0565\u0580\u0568":1,"\u0586\u056b\u056c\u057f\u0580\u0578\u0582\u0574":7,"\u0587":7,appnam:[],changelog:0,dupeguru:[1,3],help:3,indic:3,tabl:3,todo:[1,2,7]}}) \ No newline at end of file diff --git a/help/ru/.buildinfo b/help/ru/.buildinfo new file mode 100644 index 00000000..2523ccb9 --- /dev/null +++ b/help/ru/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 35135e2badb34a9c4bb7d40ecd0c313e +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/help/ru/.doctrees/changelog.doctree b/help/ru/.doctrees/changelog.doctree new file mode 100644 index 00000000..eb69a174 Binary files /dev/null and b/help/ru/.doctrees/changelog.doctree differ diff --git a/help/ru/.doctrees/environment.pickle b/help/ru/.doctrees/environment.pickle new file mode 100644 index 00000000..0989adcb Binary files /dev/null and b/help/ru/.doctrees/environment.pickle differ diff --git a/help/ru/.doctrees/faq.doctree b/help/ru/.doctrees/faq.doctree new file mode 100644 index 00000000..ad8380a7 Binary files /dev/null and b/help/ru/.doctrees/faq.doctree differ diff --git a/help/ru/.doctrees/folders.doctree b/help/ru/.doctrees/folders.doctree new file mode 100644 index 00000000..5af0721b Binary files /dev/null and b/help/ru/.doctrees/folders.doctree differ diff --git a/help/ru/.doctrees/index.doctree b/help/ru/.doctrees/index.doctree new file mode 100644 index 00000000..f8233282 Binary files /dev/null and b/help/ru/.doctrees/index.doctree differ diff --git a/help/ru/.doctrees/preferences.doctree b/help/ru/.doctrees/preferences.doctree new file mode 100644 index 00000000..4c901948 Binary files /dev/null and b/help/ru/.doctrees/preferences.doctree differ diff --git a/help/ru/.doctrees/quick_start.doctree b/help/ru/.doctrees/quick_start.doctree new file mode 100644 index 00000000..fc2099ae Binary files /dev/null and b/help/ru/.doctrees/quick_start.doctree differ diff --git a/help/ru/.doctrees/reprioritize.doctree b/help/ru/.doctrees/reprioritize.doctree new file mode 100644 index 00000000..c8618053 Binary files /dev/null and b/help/ru/.doctrees/reprioritize.doctree differ diff --git a/help/ru/.doctrees/results.doctree b/help/ru/.doctrees/results.doctree new file mode 100644 index 00000000..6451b38d Binary files /dev/null and b/help/ru/.doctrees/results.doctree differ diff --git a/help/ru/_sources/changelog.rst.txt b/help/ru/_sources/changelog.rst.txt new file mode 100644 index 00000000..b1fc6f65 --- /dev/null +++ b/help/ru/_sources/changelog.rst.txt @@ -0,0 +1,705 @@ +:tocdepth: 1 + +Changelog +========= + +**About the word "crash":** When reading this changelog, you might be alarmed at the number of fixes +for "crashes". Be aware that when the word "crash" is used here, it refers to "soft crashes" which +don't cause the application to quit. You simply get an error window that asks you if you want to +send the crash report to Hardcoded Software. Crashes that cause the application to quit are called +"hard crashes" in this changelog. + + +4.0.3 (2016-11-24) +---------------------- + +* Add new picture cache backend: shelve +* Make shelve picture cache backend the active one on MacOS to fix `#394 `__ more + elegantly. [cocoa] +* Remove Sparkle (auto-updates) due to technical limitations. [cocoa] + + +4.0.2 (2016-10-09) +---------------------- + +* Fix systematic crash in Picture Mode under MacOS Sierra. (`#394 `__) +* No change for Linux. Just keeping version in sync. + + +4.0.1 (2016-08-24) +---------------------- + +* Add Greek localization, by Gabriel Koutilellis. (`#382 `__) +* Fix localization base path. [qt] (`#378 `__) +* Fix broken load results dialog. [qt] +* Fix crash on load results. [cocoa] (`#380 `__) +* Save preferences more predictably. [qt] (`#379 `__) +* Fix picture mode's fuzzy block scanner threshold. (`#387 `__) + + +4.0.0 (2016-07-01) +---------------------- + +* Merge Standard, Music and Picture editions in the same application! +* Improve documentation. (`#294 `__) +* Add Polish, Korean, Spanish and Dutch localizations. +* qt: Fix wrong use_regexp option propagation to core. (`#295 `__) +* qt: Fix progress window mistakenly showing up on startup. (`#357 `__) +* Bump Python requirement to v3.4. +* Bump OS X requirement to 10.8 +* Drop Windows support, maybe temporarily. + `Details `__-11-01>`_ +* cocoa: Drop iPhoto, Aperture and iTunes support. Was unmaintained and obsolete. +* Drop "Audio Contents" scan type. Was confusing and seldom useful. +* Change license to GPLv3 + + +3.9.1 (2014-10-17) +---------------------- + +* Fixed ``AttributeError: 'ComboboxModel' object has no attribute 'reset'``. [Linux, Windows] (`#254 `__) +* Fixed ``PermissionError`` on saving results. (`#266 `__) +* Fixed a build problem introduced by Sphinx 1.2.3. +* Updated German localisation, by Frank Weber. + + +3.9.0 (2014-04-19) +---------------------- + +* This is mostly a dependencies upgrade. +* Upgraded to Python 3.3. +* Upgraded to Qt 5. +* Minimum Windows version is now Windows 7 64bit. +* Minimum Ubuntu version is now 14.04. +* Minimum OS X version is now 10.7 (Lion). +* ... But with a couple of little improvements. +* Improved documentation. +* Overwrite subfolders' state when setting states in folder dialog (`#248 `__) +* The error report dialog now brings the user to Github issues. + + +3.8.0 (2013-12-07) +---------------------- + +* Disable symlink/hardlink deletion option when not relevant. (`#247 `__) +* Make Cmd+A select all folders in the Folder Selection dialog. [Mac] (`#228 `__) +* Make non-numeric delta comparison case insensitive. (`#239 `__) +* Fix surrogate-related UnicodeEncodeError on CSV export. (`#210 `__) +* Fixed crash on Dupe Count sorting with Delta + Dupes Only. (`#238 `__) +* Improved documentation. +* Important internal refactorings. +* Dropped Ubuntu 12.04 and 12.10 support. +* Removed the fairware dialog (`More Info `__). + + +3.7.1 (2013-08-19) +---------------------- + +* Fixed folder scan type, which was broken in v3.7.0. + + +3.7.0 (2013-08-17) +---------------------- + +* Improved delta values to support non-numerical values. (`#213 `__) +* Improved the Re-Prioritize dialog's UI. (`#224 `__) +* Added hardlink/symlink support on Windows Vista+. (`#220 `__) +* Dropped 32bit support on Mac OS X. +* Added Vietnamese localization by Phan Anh. + + +3.6.1 (2013-04-28) +---------------------- + +* Improved "Make Selection Reference" to make it clearer. (`#222 `__) +* Improved "Open Selected" to allow opening more than one file at once. (`#142 `__) +* Fixed a few typos here and there. (`#216 `__ `#225 `__) +* Tweaked the fairware dialog (`More Info `__). +* Added Arch Linux packaging +* Added a 64-bit build for Windows. +* Improved Russian localization by Kyrill Detinov. +* Improved Brazilian localization by Victor Figueiredo. + + +3.6.0 (2012-08-08) +---------------------- + +* Added "Export to CSV". (`#189 `__) +* Added "Replace with symlinks" to complement "Replace with hardlinks". [Mac, Linux] (`#194 `__) +* dupeGuru now tells how many duplicates were affected after each re-prioritization operation. (`#204 `__) +* Added Longest/Shortest filename criteria in the re-prioritize dialog. (`#198 `__) +* Fixed result table cells which mistakenly became writable in v3.5.0. [Mac] (`#203 `__) +* Fixed "Rename Selected" which was broken since v3.5.0. [Mac] (`#202 `__) +* Fixed a bug where "Reset to Defaults" in the Columns menu wouldn't refresh menu items' marked state. +* Added Brazilian localization by Victor Figueiredo. + + +3.5.0 (2012-06-01) +---------------------- + +* Added a Deletion Options panel. +* Greatly improved memory usage for big scans. +* Added a keybinding for the filter field. (`#182 `__) [Mac] +* Upgraded minimum requirements for Ubuntu to 12.04. + + +3.4.1 (2012-04-14) +---------------------- + +* Fixed the "Folders" scan type. [Mac] +* Fixed localization issues. [Windows, Linux] + + +3.4.0 (2012-03-29) +---------------------- + +* Improved results window UI. [Windows, Linux] +* Added a dialog to edit the Ignore List. +* Added the ability to sort results by "marked" status. +* Fixed "Open with default application". (`#190 `__) +* Fixed a bug where there would be a false reporting of discarded matches. (`#195 `__) +* Fixed various localization glitches. +* Fixed hard crashes on crash reporting. (`#196 `__) +* Fixed bug where the details panel would show up at inconvenient places in the screen. [Windows, Linux] + + +3.3.3 (2012-02-01) +---------------------- + +* Fixed crash on adding some folders. [Mac OS X] +* Added Ukrainian localization by Yuri Petrashko. + + +3.3.2 (2012-01-16) +---------------------- + +* Fixed random hard crashes (yeah, again). [Mac OS X] +* Fixed crash on Export to HTML. [Windows, Linux] +* Added Armenian localization by Hrant Ohanyan. +* Added Russian localization by Igor Pavlov. + + +3.3.1 (2011-12-02) +---------------------- + +* Fixed a couple of nasty crashes. + + +3.3.0 (2011-11-30) +---------------------- + +* Added multiple-selection in folder selection dialog for a more efficient folder removal. (`#179 `__) +* Fixed a crash in the prioritize dialog. (`#178 `__) +* Fixed a bug where mass marking with a filter would mark more than filtered duplicates. (`#181 `__) +* Fixed random hard crashes. [Mac OS X] (`#183 `__ `#184 `__) +* Added Czech localization by Aleš Nehyba. +* Added Italian localization by Paolo Rossi. + + +3.2.1 (2011-10-02) +---------------------- + +* Fixed a couple of broken action bindings from v3.2.0. + + +3.2.0 (2011-09-27) +---------------------- + +* Added duplicate re-prioritization dialog. (`#138 `__) +* Added font size preference for duplicate table. (`#82 `__) +* Added Quicklook support. [Mac OS X] (`#21 `__) +* Improved behavior of Mark Selected. (`#139 `__) +* Improved filename sorting. (`#169 `__) +* Added Chinese (Simplified) localization by Eric Dee. +* Tweaked the fairware system. +* Upgraded minimum requirements to OS X 10.6 and Ubuntu 11.04. + + +3.1.2 (2011-08-25) +---------------------- + +* Fixed a bug preventing the Folders scan from working. (`#172 `__) + + +3.1.1 (2011-08-24) +---------------------- + +* Added German localization by Gregor Tätzner. +* Improved OS X Lion compatibility. [Mac OS X] +* Made the file collection phase cancellable. (`#168 `__) +* Fixed glitch in folder window upon selecting a folder state. [Windows, Linux] (`#165 `__) +* Fixed a text coloring glitch in the results. (`#156 `__) +* Fixed glitch in the sorting feature of the Folder column. (`#161 `__) +* Make sure that saved results have the ".dupeguru" extension. [Linux] (`#157 `__) + + +3.1.0 (2011-04-16) +---------------------- + +* Added the "Folders" scan type. (`#89 `__) +* Fixed a couple of crashes. (`#140 `__ `#149 `__) + + +3.0.2 (2011-03-16) +---------------------- + +* Fixed crash after removing marked dupes. (`#140 `__) +* Fixed crash on error handling. [Windows] (`#144 `__) +* Fixed crash on copy/move. [Windows] (`#148 `__) +* Fixed crash when launching dupeGuru from a very long folder name. [Mac OS X] (`#119 `__) +* Fixed a refresh bug in directory panel. (`#153 `__) +* Improved reliability of the "Send to Trash" operation. [Linux] +* Tweaked Fairware reminders. + + +3.0.1 (2011-01-27) +---------------------- + +* Restored the context menu which had been broken in 3.0.0. [Mac OS X] (`#133 `__) +* Fixed a bug where an "unsaved results" warning would be issued on quit even with empty results. (`#134 `__) +* Removed focus from the cancel button in the progress dialog to avoid accidental cancellations. [Mac OS X] (`#135 `__) +* Folders added through drag and drop are added to the recent folders list. (`#136 `__) +* Added a debugging mode. (`#132 `__) +* Fixed french localization glitches. + + +3.0.0 (2011-01-24) +---------------------- + +* Re-designed the UI. (`#129 `__) +* Internationalized dupeGuru and localized it to french. (`#32 `__) +* Changed the format of the help file. (`#130 `__) + + +2.12.3 (2011-01-01) +---------------------- + +* Fixed bug causing results to be corrupted after a scan cancellation. (`#120 `__) +* Fixed crash when fetching Fairware unpaid hours. (`#121 `__) +* Fixed crash when replacing files with hardlinks. (`#122 `__) + + +2.12.2 (2010-10-05) +---------------------- + +* Fixed delta column colors which were broken since 2.12.0. +* Fixed column sorting crash. (`#108 `__) +* Fixed occasional crash during scan. (`#106 `__) + + +2.12.1 (2010-09-30) +---------------------- + +* Re-licensed dupeGuru to BSD and made it `Fairware `__. + + +2.12.0 (2010-09-26) +---------------------- + +* Improved UI with a little revamp. +* Added the possibility to place hardlinks to references after having deleted duplicates. [Mac OS X, Linux] (`#91 `__) +* Added an option to ignore duplicates hardlinking to the same file. [Mac OS X, Linux] (`#92 `__) +* Added multiple selection in the "Add Directory" dialog. [Mac OS X] (`#105 `__) +* Fixed a bug preventing drag & drop from working in the Directories panel. [Windows, Linux] + + +2.11.1 (2010-08-26) +---------------------- + +* Fixed HTML exporting which was broken in 2.11.0. + + +2.11.0 (2010-08-18) +---------------------- + +* Added the ability to save results (and reload them) at arbitrary locations. +* Improved the way reference files in dupe groups are chosen. (`#15 `__) +* Remember size/position of all windows between launches. (`#102 `__) +* Fixed a bug sometimes preventing dupeGuru from reloading previous results. +* Fixed a bug sometimes causing the progress dialog to be stuck there. [Mac OS X] (`#103 `__) +* Removed the Creation Date column, which wasn't displaying the correct value anyway. (`#101 `__) + + +2.10.1 (2010-07-15) +---------------------- + +* Fixed a couple of crashes. (`#95 `__, `#97 `__, `#100 `__) + + +2.10.0 (2010-04-13) +---------------------- + +* Improved error messages when files can't be sent to trash, moved or copied. +* Added a custom command invocation action. (`#12 `__) +* Filters are now applied on whole paths. (`#4 `__) + + +2.9.2 (2010-02-10) +---------------------- + +* dupeGuru is now 64-bit on Mac OS X! +* Fixed a crash upon quitting when support folder is not present. (`#83 `__) +* Fixed a crash during sorting. (`#85 `__) +* Fixed selection glitches, especially while renaming. (`#93 `__) + + +2.9.1 (2010-01-13) +---------------------- + +* Improved memory usage for Contents scans. (`#75 `__) +* Improved scanning speed when ref directories are involved. (`#77 `__) +* Show a message dialog at the end of the scan if no duplicates are found. (`#81 `__) +* Fixed a bug sometimes causing the small files threshold pref to be ignored. [Mac OS X] (`#75 `__) + + +2.9.0 (2009-11-03) +---------------------- + +* Significantly improved speed and memory usage of big contents-based scans. +* Added drag & drop support in the Directories panel. (`#9 `__) +* Fixed a bug causing dupeGuru to be confused if a scanned file was moved during the scan. (`#72 `__) +* Dropped support for Mac OS X 10.4 (Tiger) + + +2.8.2 (2009-10-14) +---------------------- + +* Improved directory selection in the Directories panel (Windows). (`#56 `__) +* Fixed a bug preventing dupeGuru from starting on certain machines (Windows). (`#68 `__) +* Fixed a crash during very big scans. (`#70 `__) + + +2.8.1 (2009-10-02) +---------------------- + +* Fixed crash with filtering when regular expressions were enabled. (`#60 `__) +* Fixed crash when setting directories' state. (Mac OS X) (`#66 `__) +* Fixed crash with Make Reference when certain filters are applied. (Mac OS X) (`#55 `__) +* Improved error handling during delete/move/copy actions. (`#62 `__ `#65 `__) + + +2.8.0 (2009-09-07) +---------------------- + +* Added support for all kinds of bundle (not just applications) (Mac OS X) (`#11 `__) +* Re-introduced the Export to XHTML feature to Windows. (`#14 `__) +* Improved Export to XHTML speed. (`#14 `__) +* Improved Contents scanning speed for large files. (`#33 `__) +* Improved the grouping algorithm to reduce the number of discarded files in non-exact scans. (`#51 `__) +* Stopped showing the same file on the 2 sides of the details panel when a ref file is selected. (`#50 `__) +* Fixed crashes in the Directories panel. (`#46 `__) + + +2.7.3 (2009-06-20) +---------------------- + +* Fixed bugs with selection being jumpy during "Make Reference" actions and Power Marker + switches. (`#3 `__) +* Fixed crash happening when a file with non-roman characters couldn't be analyzed. (`#30 `__) +* Fixed crash sometimes happening during the file collection phase in scanning. (`#38 `__) +* Restored double-click and right-click behavior lost in the PyQt move (Windows). (`#34 `__ `#35 `__) + + +2.7.2 (2009-06-10) +---------------------- + +* Fixed an occasional crash on Copy/Move operations. (`#16 `__) +* Added automatic exclusion for sensible folders (like system folders). (`#20 `__) +* Fixed an occasional crash when application files were part of the results (Mac OS X). (`#25 `__) + + +2.7.1 (2009-05-29) +---------------------- + +* Fixed a bug causing crashes when having application files in the results. +* Fixed a bug causing a GUI freeze at the beginning of a scan with a lot of files. +* Fixed a bug that sometimes caused a crash when an action was cancelled, and then started again. + + +2.7.0 (2009-05-25) +---------------------- + +* Converted the Windows GUI to Qt. +* Improved the reliability of the scanning process. + + +2.6.1 (2009-03-27) +---------------------- + +* **Fixed** an occasional crash caused by permission issues. +* **Fixed** a bug where the "X discarded" notice would show a too large number of discarded + duplicates. + + +2.6.0 (2008-09-10) +---------------------- + +* **Added** a small file threshold preference. +* **Added** a notice in the status bar when matches were discarded during the scan. +* **Improved** duplicate prioritization (smartly chooses which file you will keep). +* **Improved** scan progress feedback. +* **Improved** responsiveness of the user interface for certain actions. + + +2.5.4 (2008-08-10) +---------------------- + +* **Improved** the speed of results loading and saving. +* **Fixed** a crash sometimes occurring during duplicate deletion. + + +2.5.3 (2008-07-08) +---------------------- + +* **Improved** unicode handling for filenames. dupeGuru will now find a lot more duplicates if your files have non-ascii characters in it. +* **Fixed** "Clear Ignore List" crash in Windows. + + +2.5.2 (2008-01-10) +---------------------- + +* **Improved** the handling of low memory situations. +* **Improved** the directory panel. The "Remove" button changes to "Put Back" when an excluded directory is selected. +* **Improved** scan, delete and move speed in situations where there were a lot of duplicates. +* **Fixed** occasional crashes when moving bundles (such as .app files). +* **Fixed** occasional crashes when moving a lot of files at once. + + +2.5.1 (2007-11-22) +---------------------- + +* **Added** the "Remove empty folders" option. +* **Fixed** results load/save issues. +* **Fixed** occasional status bar inaccuracies when the results are filtered. + + +2.5.0 (2007-09-15) +---------------------- + +* **Added** post scan filtering. +* **Fixed** issues with the rename feature under Windows +* **Fixed** some user interface annoyances under Windows + + +2.4.8 (2007-04-14) +---------------------- + +* **Improved** UI responsiveness (using threads) under Mac OS X. +* **Improved** result load/save speed and memory usage. + + +2.4.7 (2007-03-10) +---------------------- + +* **Fixed** a "bad file descriptor" error occasionally popping up. +* **Fixed** a bug with non-latin directory names. + + +2.4.6 (2007-02-10) +---------------------- + +* **Added** Re-orderable columns. In fact, I re-added the feature which was lost in the C# conversion in 2.4.0 (Windows). +* **Changed** the behavior of the scanning engine when setting the hardness to 100. It will now only match files that have their words in the same order. +* **Fixed** a bug with all the Delete/Move/Copy actions with certain kinds of files. + + +2.4.5 (2007-01-11) +---------------------- + +* **Fixed** a bug with the Move action. + + +2.4.4 (2007-01-07) +---------------------- + +* **Fixed** a "ghosting" bug. Dupes deleted by dupeGuru would sometimes come back in subsequent scans (Windows). +* **Fixed** bugs sometimes making dupeGuru crash when marking a dupe (Windows). +* **Fixed** some minor visual glitches (Windows). + + +2.4.3 (2006-12-08) +---------------------- + +* **Fixed** a mishandling of ".app" files (OS X). +* **Fixed** a bug preventing files from "reference" directories to be displayed in blue in the results (Windows). +* **Fixed** a bug preventing some files to be sent to the recycle bin (Windows). +* **Fixed** a bug in the packaging preventing certain Windows configurations to start dupeGuru at all. + + +2.4.2 (2006-11-18) +---------------------- + +* **Fixed** a bug with directory states. + + +2.4.1 (2006-11-15) +---------------------- + +* **Fixed** a bug causing the ignore list not to be saved. +* **Fixed** a bug sometimes making delete and move operations stall. + + +2.4.0 (2006-11-10) +---------------------- + +* **Changed** the Windows interface. It is now .NET based. +* **Added** an auto-update feature to the windows version. +* **Changed** the way power marking works. It is now a mode instead of a separate window. +* **Changed** the "Size (MB)" column for a "Size (KB)" column. The values are now "ceiled" instead of rounded. Therefore, a size "0" is now really 0 bytes, not just a value too small to be rounded up. It is also the case for delta values. +* **Removed** the min word length/count options. These came from Mp3 Filter, and just aren't used anymore. Word weighting does pretty much the same job. + + +2.3.4 (2006-11-07) +---------------------- + +* **Improved** speed and memory usage of the scanning engine, again. Does it mean there was a lot of improvements to be made? Nah... + + +2.3.3 (2006-11-02) +---------------------- + +* **Improved** speed and memory usage of the scanning engine, especially when the scan results in a lot of duplicates. +* Now I wonder if Sparkle is going to work well... + + +2.3.2 (2006-10-16) +---------------------- + +* **Added** an auto-update feature in the Mac OS X version (with Sparkle). +* **Fixed** a bug preventing some duplicate reports to be created correctly under Windows. + + +2.3.1 (2006-10-02) +---------------------- + +* **Fixed** a bug preventing some duplicates to be found, especially when scanning lots of files. + + +2.3.0 (2006-09-22) +---------------------- + +* **Added** XHTML export feature. + + +2.2.10 (2006-08-31) +---------------------- + +* **Added** sticky columns. +* **Fixed** an issue with file caching between scans. +* **Fixed** an issue preventing some duplicates from being deleted/moved/copied. + + +2.2.9 (2006-08-27) +---------------------- + +* **Fixed** an issue with ignore list and unicode. +* **Fixed** an issue with file attribute fetching sometimes causing dupeGuru to crash. +* **Fixed** an issue in the directories panel under Windows. + + +2.2.8 (2006-08-17) +---------------------- + +* **Fixed** an issue in the duplicate seeking engine preventing some duplicates to be found. + + +2.2.7 (2006-08-12) +---------------------- + +* **Improved** unicode support. +* **Improved** the "Reveal in Finder" ("Open Containing Folder" in Windows) feature so it selects the file in the folder it opens. + + +2.2.6 (2006-08-07) +---------------------- + +* **Improved** the ignore list system. +* dupeGuru is now a Universal application on Mac OS X. + + +2.2.5 (2006-07-26) +---------------------- + +* **Improved** application (.app) dupe detection on Mac OS X. +* **Fixed** an issue that occasionally made dupeGuru crash on startup. + + +2.2.4 (2006-06-27) +---------------------- + +* **Fixed** an issue with Move and Copy features. + + +2.2.3 (2006-06-15) +---------------------- + +* **Improved** duplicate scanning speed. +* **Added** a warning that a file couldn't be renamed if a file with the same name already exists. + + +2.2.2 (2006-06-07) +---------------------- + +* **Added** "Rename Selected" feature. +* **Fixed** some minor issues with "Reload Last Results" feature. +* **Fixed** ignore list issues. + + +2.2.1 (2006-05-22) +---------------------- + +* **Fixed** occasional progress bar woes under Windows. +* **Fixed** a bug in the registration system under Windows. +* Nothing has been changed in the Mac OS X version, but I want to keep version in sync. + + +2.2.0 (2006-05-10) +---------------------- + +* **Added** destination path re-creation options. +* **Added** an ignore list. +* **Changed** the main icon. +* **Improved** dramatically the delta values feature. + + +2.1.2 (2006-04-18) +---------------------- + +* **Added** the "Match similar words" option. +* **Fixed** Power marking issues under Mac. + + +2.1.1 (2006-04-14) +---------------------- + +* **Added** the "Display delta values" option. +* **Improved** Power marking sorting speed under Mac. +* **Fixed** Power marking sorting issues. + + +2.1.0 (2006-04-03) +---------------------- + +* **Added** the Power Marker feature. +* **Fixed** a column sorting bug. The results would sometimes lose their sort order. +* **Fixed** a bug with the Make Reference feature. The results sometimes wasn't correctly refreshed after the reference switch. + + +2.0.1 (2006-03-23) +---------------------- + +* **Fixed** an issue occasionally occurring when trying to reload results from removable media that is no longer present. + + +2.0.0 (2006-03-17) +---------------------- + +* Complete rewrite. +* Now runs on Mac OS X. + + +1.0.0 (2004-09-24) +---------------------- + +* Initial release. + diff --git a/help/ru/_sources/faq.rst.txt b/help/ru/_sources/faq.rst.txt new file mode 100644 index 00000000..e31d119f --- /dev/null +++ b/help/ru/_sources/faq.rst.txt @@ -0,0 +1,116 @@ +Часто задаваемые вопросы +========================== + +.. topic:: Что такое dupeGuru? + + .. only:: edition_se + + dupeGuru это инструмент для поиска дубликатов файлов на вашем компьютере. Он может сканировать либо имен файлов или контента.Имя файла функций сканирования нечеткого соответствия алгоритма, который позволяет найти одинаковые имена файлов, даже если они не совсем то же самое. + + .. only:: edition_me + + dupeGuru Music Edition представляет собой инструмент для поиска дублирующихся песен в вашей музыкальной коллекции. Он может строить свою сканирование файлов, тегам или содержания.Имя файла и тэг проверяет функция нечеткого соответствия алгоритм, который может находить дубликаты файлов или теги, даже если они не совсем то же самое. + + .. only:: edition_pe + + dupeGuru Picture Edition (PE для краткости) представляет собой инструмент для поиска дубликатов фотографий на вашем компьютере. Не только он может найти точные соответствия, но он также может найти дубликаты среди фотографий разного рода (PNG, JPG, GIF и т.д..) И качество. + +.. topic:: Что делает его лучше, чем другие сканеры дублировать? + + Сканирования является чрезвычайно гибкой. Вы можете настроить его, чтобы действительно получить, каких результатов вы хотите. Вы можете прочитать больше о опция настройки dupeGuru в :doc:`Настройки `. + +.. topic:: Насколько безопасно использовать dupeGuru? + + Очень безопасной. dupeGuru был разработан, чтобы убедиться, что вы не удаляете файлы, которые вы не хотели удалить. Во-первых, существует система отсчета папку, которая позволяет определить папки, в которых вы абсолютно не хотите dupeGuru, чтобы вы удаляете файлы там, и тогда есть система контрольной группы, что гарантирует, что вы всегда держать по крайней мере один член группы дубликатов. + +.. topic:: Каковы ограничения демо dupeGuru? + + В демо-режиме, вы можете только выполнять действия над 10 дубликаты сразу. в + `Fairware `_ режиме, однако, Есть никаких ограничений. + +.. topic:: Знак коробку файл я хочу удалить отключена. Что я должен сделать? + + Вы не можете пометить ссылки (первый файл) дубликат группы. Однако то, что вы можете сделать, заключается в содействии дублировать файл справки. Таким образом, если файл, который Вы хотите, чтобы отметить это ссылки, выделите дубликатов файлов в группу, которую вы хотите продвигать на ссылку, и нажмите на кнопку **Действия -> Добавить выбранной ссылки** . Если ссылка файл из папки ссылки (имя файла написаны на синими буквами), вы не можете удалить его из исходного положения. + +.. topic:: У меня есть папка, из которой я действительно не хочу, чтобы удалить файлы. + + IЕсли вы хотите быть уверены, что dupeGuru никогда не будет удалять файл из определенной папки, убедитесь, что установили в состояние **Ссылка** на: документ: `папки`. + +.. topic:: Что это за '(X отбрасывается) "уведомление в строке состояния? + + В некоторых случаях, несколько матчей не включены в окончательные результаты по соображениям безопасности. Позвольте мне привести пример. У нас есть 3 файла: A, B и C. Мы сканируем их с помощью фильтра низких твердости.Сканер определяет, что матчи с B, матчи с С, но делает B ** не ** матч с С. При этом, dupeGuru имеет вид проблемы. Она не может создать дубликат группы А, В и С в это, потому что не все файлы в группе будет соответствовать вместе. Это может создать 2 группы: одна группа AB, а затем одна группа AC, но это не будет, по соображениям безопасности. Давайте думать об этом: если Б не совпадает с С, она, вероятно, означает, что либо B, C или оба на самом деле не дубликаты. Если не было бы 2 группы (АВ и АС), вы бы в конечном итоге удалить оба B и C. И если один из них не дублировать, что на самом деле не то, что вы хотите делать, правильно? Так что dupeGuru делает в таком случае является, чтобы отменить матч AC (и добавляет уведомление в строке состояния). Таким образом, если вы удалите B и повторно запустить сканирование, вам придется соответствовать переменного тока в следующий результат. + +.. topic:: Я хочу, чтобы отметить все файлы из определенной папки. Что я могу сделать? + + Включить: документ: `обманутые Только <результаты>` режим и нажать на папку колонки для сортировки дубликатов по папкам. Затем он будет легким для вас, чтобы выбрать все дубликаты из той же папке, а затем нажать клавишу пробел, чтобы отметить все выбранные дубликатов. + +.. only:: edition_se or edition_pe + + .. topic:: Я хочу, чтобы удалить все файлы, которые более 300 Кб от их ссылке на файл. Что я могу сделать? + + * Включить :doc:`Только обманутые ` режим. + * Включить **Значения Делта** режим. + * Нажмите на "размер" столбца для сортировки результатов по размеру. + * Выбрать все дубликаты ниже -300. + * Нажмите на **Удалить выбранные из результатов**. + * Выбрать все дубликаты более 300. + * Нажмите на **Удалить выбранные из результатов**. + + .. topic:: Я хочу, чтобы мои последние измененные файлы файлы справки. Что я могу сделать? + + * Включить: документ: `обманутые Только <результаты>` режим. + * Включить **Значения делта** режим. + * Нажмите на колонку "Модификация" для сортировки результатов по дате изменения. + * Нажмите на колонку "Модификация" снова изменить порядок сортировки. + * Выберите все дубликаты на 0. + * Нажмите на **Сделать выбранной ссылки**. + + .. topic:: Я хочу, чтобы отметить все дубликаты, содержащие слово "копия". Как мне это сделать? + + * **Windows**: Нажмите на **Действия -> Применить фильтр**, затем введите "копия", нажмите кнопку ОК. + * **Mac OS X**: тип "копия" в "Фильтр" поле на панели инструментов. + * Нажмите на **Отметить -> Отметить все**. + +.. only:: edition_me + + .. topic:: Я хочу, чтобы удалить все песни, которые более чем на 3 секунды от своей ссылке на файл. Что я могу сделать? + + * Включить: документ: `обманутые Только <результаты>` режим. + * Включить **Значения делта** режим. + * Нажмите на "Время" колонку для сортировки результатов по времени. + * Выберите все дубликаты ниже -00:03. + * Нажмите на **Удалить выбранные из результатов**. + * Выберите все дубликаты на 00:03. + * Нажмите на **Удалить выбранные из результатов**. + + .. topic:: Я хочу, чтобы мой высокий битрейт файлов песни ссылки. Что я могу сделать? + + * Включить: документ: `обманутые Только <результаты>` режиме + * Включить **Значения делта** режим. + * Нажмите на кнопку "Битрейт" колонку для сортировки результатов по битрейт. + * Нажмите на кнопку "Битрейт" колонна снова изменить порядок сортировки. + * Выберите все дубликаты на 0. + * Нажмите на **Сделать выбранной ссылки**. + + .. topic:: Я не хочу [жить] и [ремикс] версии моих песен считаться дубликатами. Как мне это сделать? + + Если ваше сравнение порог достаточно низким, вы, вероятно, в конечном итоге с живой и ремикс версии ваших песен в своих результатах. Там вы ничего не можете сделать, чтобы предотвратить это, но есть кое-что можно сделать, чтобы легко удалить их со своего результаты после сканирования: после сканирования, фильтрации. Если, например, вы хотите удалить все песни с чем-либо в квадратных скобках []: + + * **Windows**: Нажмите на **Действия -> Применить фильтр**, а затем введите "[*]", нажмите кнопку ОК. + * **Mac OS X**: Тип "[*]" в "Фильтр" поле на панели инструментов. + * Нажмите на Отметить **-> Отметить все**. + * Нажмите на **Действия -> Удалить выбранные из результатов**. + +.. topic:: Я пытался отправить свои дубликаты в корзину, но dupeGuru говорит мне, он не может это сделать. Почему? Что я могу сделать? + + Большую часть времени, поэтому dupeGuru не можете отправлять файлы в корзину из-за права доступа к файлам. Вы должны написать * * разрешения на файлы, которые вы хотите отправить в корзину. Если вы не знакомы с командной строкой, вы можете использовать утилиты, такие как `BatChmod ` _ исправить Ваши права. + + Если dupeGuru еще дает вам неприятности после фиксации ваших прав, было несколько случаев, когда с помощью "Перемещение Помечено к ..." в качестве обходного пути сделали свое дело. Таким образом, вместо отправки файлов в корзину, вы посылаете их во временную папку с "Переместить Отмеченные к ..." действия, а затем вы удалите эту временную папку вручную. + + .. only:: edition_pe + + Если вы пытаетесь удалить *Iphoto* фотографии, то причина сбоя иная.Удаление не выполняется, так dupeGuru не может общаться с Iphoto. Учтите, что для удаления корректной работы, вы не должны играть вокруг Iphoto в то время как dupeGuru работает. Кроме того, иногда, система Applescript, кажется, не знают, где найти Iphoto запустить его. Это может помочь в таких случаях для запуска Iphoto *до* вы посылаете дубликатов в корзину. + + Если все это не так, `контакт с поддержки HS `_, мы поможем Вас. + +.. todo:: This FAQ qestion is outdated, see english version. diff --git a/help/ru/_sources/folders.rst.txt b/help/ru/_sources/folders.rst.txt new file mode 100644 index 00000000..296c3b87 --- /dev/null +++ b/help/ru/_sources/folders.rst.txt @@ -0,0 +1,25 @@ +Выбор папки +================ + +Первое окно, вы видите, когда вы запускаете dupeGuru это окно выбора папки. Это окно содержит список папок, которые будут сканироваться при нажатии на **Scan**. + +Это окно довольно проста в использовании. Если вы хотите добавить папку, нажмите на кнопку **+**. Если вы добавили папки прежде, всплывающее меню со списком последних папки добавил появится. Вы можете нажать на одну из них, чтобы добавить его прямо в свой список. Если нажать на первый пункт всплывающего меню, **Добавить новую папку ...**, вам будет предложено ввести папку добавить. Если вы никогда не добавляется папка, не появится меню, и вы будете непосредственно будет предложено ввести новую папку добавить. + +Альтернативный способ для добавления папок в список, чтобы перетащить их в списке. + +Чтобы удалить папку, выберите папку, удалить, и нажмите на **-**. Если папке выбирается при нажатии кнопки, выбранной папки будет установлен в ** ** исключены состояния (см. ниже), а не удален. + +Папка государств +---------------- + +Каждая папка может находиться в одном из этих 3-х государств: + +* **Нормальный:** дубликаты найдены в эту папку можно удалить. +* **Справка:** Дубликаты найти в этой папке не может **быть удалены** . Файлы из этой папки можно только в конечном итоге в **ссылка** позиция в группе обмануть. Если более чем один файл из папки ссылку в конечном итоге в той же группе обмануть, только один, будут сохранены.Другие будут удалены из группы. +* **Не включено:** Файлы в этом каталоге не будет включен в проверку. + +Состояние по умолчанию к папке, конечно, **Нормальный**. Вы можете использовать **Ссылка** состояние для папки, если вы хотите быть уверены, что вы не будете удалять любые файлы из него. + +Когда вы устанавливаете состояние каталог, все подпапки этой папки автоматически наследует это состояние, если явно не включенное состояние подпапку в. + +.. todo:: Add iPhoto/Aperture/iTunes libraries notes diff --git a/help/ru/_sources/index.rst.txt b/help/ru/_sources/index.rst.txt new file mode 100644 index 00000000..002af623 --- /dev/null +++ b/help/ru/_sources/index.rst.txt @@ -0,0 +1,46 @@ +dupeGuru help +=============== + +.. only:: edition_se + + Этот документ также доступна на `французском `__, `немецком `__ и `армянский `__. + +.. only:: edition_me + + Этот документ также доступна на `французском `__, `немецкий `__ и `армянский `__. + +.. only:: edition_pe + + Этот документ также доступна на `французском `__, `немецкий `__ и `армянский `__. + +.. only:: edition_se or edition_me + + dupeGuru есть инструмент для поиска дубликатов файлов на вашем компьютере. Он может сканировать либо имен файлов или содержимого.Имя файла функций сканирования нечеткого соответствия алгоритма, который позволяет найти одинаковые имена файлов, даже если они не совсем то же самое. + +.. only:: edition_pe + + dupeGuru Picture Edition (PE для краткости) представляет собой инструмент для поиска дубликатов фотографий на вашем компьютере. Не только он может найти точные соответствия, но он также может найти дубликаты среди фотографий разного рода (PNG, JPG, GIF и т.д..) И качество. + +Хотя dupeGuru может быть легко использована без документации, чтение этого файла поможет вам освоить его. Если вы ищете руководство для вашей первой дублировать сканирования, вы можете взглянуть на раздел :doc:`Быстрый ` Начало. + +Это хорошая идея, чтобы сохранить dupeGuru обновлен. Вы можете скачать последнюю версию на своей `homepage`_. +Содержание: + +.. toctree:: + :maxdepth: 2 + + quick_start + folders + preferences + results + reprioritize + faq + changelog + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` + +.. _homepage: https://www.hardcoded.net/dupeguru \ No newline at end of file diff --git a/help/ru/_sources/preferences.rst.txt b/help/ru/_sources/preferences.rst.txt new file mode 100644 index 00000000..7e67b6b5 --- /dev/null +++ b/help/ru/_sources/preferences.rst.txt @@ -0,0 +1,63 @@ +Предпочтения +============= + +.. only:: edition_se + + **Тип сканирования:** Этот параметр определяет, какой аспект файлы будут сравниваться в дубликат сканирования. Если выбрать **Имя файла**, dupeGuru будем сравнивать каждое имена файлов слово за слово, и, в зависимости от других параметров ниже, он будет определять, достаточно ли слов соответствие рассмотреть 2 файлов дубликатов. Если выбрать **Содержимое**, только файлы с точно такой же контент будет матч. + + **Папки** типа сканирования немного особенным. Когда вы выбираете его, dupeGuru проведет поиск дубликатов *папки* вместо того, чтобы дубликатов файлов. Для определения того, две папки, дублируют друг друга, все файлы, содержащиеся в папках будут проверяться, и если содержание **все** файлы в матче папки, папки будут считаться дубликатами. + + **Фильтра Твердость:** Если вы выбрали **Имя файла** типа сканирования, эта опция определяет, как похожи два имени должно быть для dupeGuru рассматривать их дубликатов. Если фильтр твердости, например 80, то это означает, что 80% слов из двух имен файлов должны совпадать. Для определения соответствия процент, dupeGuru первой подсчитывает общее количество слов в **обоих** файла, то подсчитать количество слов соответствия (каждое слово соответствия считаются 2), а затем разделите количество слов соответствия на общее число слов. Если результат больше или равно фильтр твердость, у нас есть дубликаты матча. Например, "ABCD" и "CDE" имеют соответствующий процент 57 (4 слова соответствия, 7 всего слов). + +.. only:: edition_me + + **Тип сканирования:** Этот параметр определяет, какой аспект файлы будут сравниваться в дубликат сканирования.Характер дублировать сканирования варьируется в зависимости от того, что вы выбираете для этой опции. + + * **Имя файла:** Каждая песня будет иметь свой файл разбит на слова, а затем каждое слово будет по сравнению с вычислить соответствующие проценты. Если этот процент выше или равна **жесткость фильтра** (см. ниже подробнее), dupeGuru рассмотрит 2 песни дубликатов. + * **Имя файла - Поля: **Как**Имя файла**, за исключением того, что как только имя файла были разделены на слова, эти слова затем группируются в поля.Разделитель полей "-".Окончательный процент соответствия будет самым низким соответствующий процент среди полей. Таким образом, "Исполнитель - Название" и "Артист - Другие Название" будет иметь соответствующий процент 50 (С **Имя файла** сканирования, это будет 75). + * **Имя файла - Поля (нет приказа):**Как**Имя файла-Поля**, кроме того, что порядок полей не имеет значения. Например, "Исполнитель - Название" и "Название - Артист" будет иметь соответствующий процент из 100 вместо 0. + * **Теги:** Этот метод считывает метки (метаданные) каждой песни и сравнить их полям. Этот метод, как Супер **- Поля**, считает низкий соответствующее поле в качестве окончательного соответствующий процент. + * **Состав:** Этот метод сканирования использовать фактическое содержание песни, чтобы определить, какие являются дубликатами. За 2 песни в соответствии с этим методом, они должны иметь точно **такой же содержания**. + * **Аудио контента:** То же содержание, но только в аудио-контент сравнивается (без метаданных). + + **Фильтра Твердость:** Если вы выбрали имя файла или тегами типа сканирования, эта опция определяет, как похожи два имени / теги должны быть для dupeGuru рассматривать их дубликатов. Если фильтр твердости, например 80, то это означает, что 80% слов из двух имен файлов должны совпадать. Для определения соответствия процент, dupeGuru первой подсчитывает общее количество слов в **обоих** файла, то подсчитать количество слов соответствия (каждое слово соответствия считаются 2), а затем разделите количество слов соответствия на общее число слов. Если результат больше или равно фильтр твердость, у нас есть дубликаты матча. Например, "ABCD" и "CDE" имеют соответствующий процент 57 (4 слова соответствия, 7 всего слов). + + **Теги для сканирования:** При использовании **Тега** Слова типа сканирования, вы можете выбрать теги, которые будут использоваться для сравнения. + +.. only:: edition_se or edition_me + + **Слово взвешивания:** Если вы выбрали **Имя файла** типа сканирования, этот вариант несколько изменений, как соответствующий процент рассчитывается. При слове взвешивания, вместо того, значение 1 в дубликат счета и общее количество слов, каждое слово имеет значение, равное количество символов, которые они имеют. При слове взвешивание, "AB CDE FGHI" и "AB CDE fghij" будет иметь соответствующий процент 53% (19 Персонажей, 10 символов, соответствующая (4 для "б" и 6 "CDE")). + + **Совпадения похожих слов:** Если вы включите эту опцию, подобные слова будут засчитаны как спички. Например, "Белая полоса" будет совпадать% из 100 вместо 66 с, что функция включена. **Внимание:** Используйте эту опцию с осторожностью. Вполне вероятно, что вы получите много ложных срабатываний в результатах при его включении. Тем не менее, это поможет вам найти дубликаты, что вы не нашли бы в противном случае.Процесс сканирования также значительно медленнее, эта опция включена. + +.. only:: edition_pe + + **Тип сканирования:** Этот параметр определяет тип сканирования, которые будут сделаны на ваши картины.**Сканирования** Содержание типа сравнивает фактическое содержание фотографий нечеткие пути (что делает его можно найти не только точными копиями, но и подобные).**EXIF Timestamp** тип сканирования смотрит на метаданные EXIF с фото (если он существует) и соответствует фотографии, которые имеют такой же. Это намного быстрее, чем сканирование содержимого. **Внимание:** Измененные фотографии часто держат же метка EXIF, так что следите за ложных срабатываний, когда вы используете, что тип сканирования. + + **Фильтра Твердость:** *Содержание тип сканирования только.* Чем больше этот параметр, "тяжелее" является фильтром (Другими словами, тем меньше результатов Вы получите). Большинство фотографий одного и того же матча качества на 100%, даже если формат отличается (PNG и JPG, например.). Однако, если вы хотите, чтобы соответствовать PNG с более низким качеством JPG, вам придется установить фильтром твердость ниже, чем 100.По умолчанию, 95, это сладкое место. + + **Совпадения рисунки разных размеров:** Если вы установите этот флажок, фотографии разных размеров будет разрешен в том же дубликат группы. + +**Можно смешивать файл вида:** Если вы установите этот флажок, дублировать группам разрешается есть файлы с различными расширениями. Если вы не проверить его, ну, они не являются! + +**Игнорировать дубликаты hardlinking в тот же файл:** Если эта опция включена, dupeGuru проверит дубликаты, чтобы увидеть если они ссылаются на тот же индексный `дескриптор `_. Если они это сделают, они не будут считаться дубликатами. (Только для OS X и Linux) + +**Использование регулярных выражений при фильтрации:** Если вы отметите этот флажок, фильтрация будет рассматривать ваш запрос фильтра, как **регулярное выражение**. Объясняя их выходит за рамки этого документа.Хорошее место для начала обучения он `regular-expressions.info `_. + +**Удаление пустых папок после удаления или перемещения:** Когда эта опция включена, папки будут удалены через файл удален или перемещен и папка пуста. + +**Копирование и перемещение:** Определяет, как операции копирования и перемещения (в меню Действия) будет себя вести. + +* **Право на назначение:** Все файлы будут отправлены непосредственно в пункт назначения, не пытаясь воссоздать исходный путь вообще. +* **Повторно относительный путь:** путь исходный файл будет воссоздан в папке назначения, вплоть до корневого выделение в панели директорей. Например, если вы добавили ``/Users/foobar/SomeFolder`` на панель Каталоги и перемещении ``/Users/foobar/SomeFolder/SubFolder/SomeFile.ext`` до места назначения ``/Users/foobar/MyDestination``, конечным пунктом назначения для файла будет ``/Users/foobar/MyDestination/SubFolder`` (``SomeFolder`` были сокращены с пути источника в конечный пункт назначения.). +* **Повторно абсолютный путь:** путь исходный файл будет воссоздан в папке назначения в полном комплекте. Например, если вы перемещаете ``/Users/foobar/SomeFolder/SubFolder/SomeFile.ext`` до места назначения ``/Users/foobar/MyDestination``, конечным пунктом назначения для файла будет ``/Users/foobar/MyDestination/Users/foobar/SomeFolder/SubFolder``. + +Во всех случаях, dupeGuru красиво ручки конфликтов имен путем добавления номера назначения имя файла, если имя файла уже существует в месте назначения. + +**Специальной команды:** Это предпочтение определяет команду, которая будет вызываться "Вызов специальной команды" действия. Вы можете ссылаться ни на какие внешние приложения через это действие. Это может быть полезно, если, например, у вас есть хорошее приложение сравниваете установлены. + +Формат команды такой же, как то, что вы должны написать в командной строке, за исключением того, что Есть 2 заполнителей: **%d** and **%r**. Эти заполнители будут заменены на путь выбран обманут (%d) и путь к ссылке на файл выбранного обмануть (%r). + +Если путь к исполняемому содержит пробелы, необходимо заключить его в "" кавычки. Вы также должны приложить заполнителей в кавычки, потому что это очень возможно, что путь к обманутых и ссылки будут содержать пробелы. Вот пример пользовательской команды: + + "C:\Program Files\SuperDiffProg\SuperDiffProg.exe" "%d" "%r" diff --git a/help/ru/_sources/quick_start.rst.txt b/help/ru/_sources/quick_start.rst.txt new file mode 100644 index 00000000..8a46e906 --- /dev/null +++ b/help/ru/_sources/quick_start.rst.txt @@ -0,0 +1,14 @@ +Быстрый старт +============= + +Чтобы вы быстро начали с dupeGuru, давайте просто делать сканирование с помощью стандартных настроек по умолчанию. + +* Запуск dupeGuru. +* Добавление папок для сканирования либо перетащить & капли или кнопку "+". +* Нажмите на **сканирование**. +* Подождите, пока процесс сканирования завершен. +* Посмотрите на каждый дубликат (файлы, которые отступом) и убедитесь, что это действительно дубликат ссылкой группы (файл выше дублировать без отступа и инвалидов окна знак). +* Если файл ложных дубликатов, выделите ее и нажмите **Действия -> Удалить выбранные из результатов**. +* Если вы уверены, что нет ложных дубликатов в результатах, нажмите на **Изменить -> Отметить Все**, а затем **Действия -> Отправить Помечено в Корзину**. + +Это только основные сканирования. Есть много настройки вы можете сделать, чтобы получить разные результаты и несколько методов изучения и изменения ваших результатов. Чтобы узнать о них, только что прочитал остальную часть этого файла справки. \ No newline at end of file diff --git a/help/ru/_sources/reprioritize.rst.txt b/help/ru/_sources/reprioritize.rst.txt new file mode 100644 index 00000000..612351a8 --- /dev/null +++ b/help/ru/_sources/reprioritize.rst.txt @@ -0,0 +1,25 @@ +Повторное приоритетов дубликатов +================================ + +dupeGuru пытается автоматически определить, какие дубликат должен отправиться в ссылку каждой группы +позиции, но иногда это делается неправильно. Во многих случаях, умный обмануть сортировки с "Ценности Дельта" +и "обманутые Только" варианты в дополнение к "Сделать выбранной ссылки" действие делает трюк, но +иногда, более мощный вариант не требуется. Здесь изменения приоритетов в диалог вступает в +играть. Вы можете вызвать его через "изменить приоритеты Результаты" пункт в меню "Действия". + +Этот диалог позволяет вам выбрать критерии, по которым ссылка обмануть будут отобраны в +каждой группе обмануть.Список доступных критериев слева и перечень критериев вы +Выбранная справа. + +Критериев категории следуют аргумент. Например, "Размер (Высший)" означает, что обмануть +с крупным размером победит. "Свойства папки (/ Foo / Bar)" означает, что обманутые в этой папке будет победить. Для добавления +критерий правом списке, сначала выберите категорию в выпадающем списке, затем выберите +subargument в приведенном ниже списке, а затем нажмите на правую стрелку кнопки. + +Порядок списка справа важно (вы можете изменить порядок элементов через перетащить и отпустить). когда +сбор обмануть для справки позицию, первый критерий используется. Если есть галстук, второй +критерий используется и так далее и так далее. Например, если ваши аргументы "Размер (высший)", а затем +"Имя файла (Не оканчивается на номер)", ссылке на файл, который будет выбран в группе будет +крупнейших файл, а если два или несколько файлов имеют одинаковый размер, который имеет имя файла с +не заканчивается номер будет использоваться. Когда все критерии привести к связи, порядок, в котором обманутые +ранее были в группе будет использоваться. \ No newline at end of file diff --git a/help/ru/_sources/results.rst.txt b/help/ru/_sources/results.rst.txt new file mode 100644 index 00000000..3fa55f2c --- /dev/null +++ b/help/ru/_sources/results.rst.txt @@ -0,0 +1,101 @@ +Результаты +========== + +Когда dupeGuru завершения сканирования на наличие дубликатов, он покажет его результаты в виде дубликата список группы. + +О дубликат группы +---------------------- + +Дубликат группа представляет собой группу файлов, которые весь матч вместе. Каждая группа имеет **ссылке** на файл и одного или более **одинаковых файлов**. Ссылки файл первый файл группы. Его марка окно отключено. Под ним, и с отступом, которые дубликатов файлов. + +Вы можете отметить дубликатов файлов, но вы никогда не можете пометить ссылки файл группы. Это мера безопасности, чтобы предотвратить dupeGuru от удаления не только повторяющиеся файлы, но их ссылки. Ты уверен, что не хочу этого, не так ли? + +Что определяет, какие файлы ссылки и какие файлы являются дубликатами сначала свою папку государства. Файл с ссылкой папка всегда будет ссылка в дубликат группы. Если все файлы из обычной папки, размер определить, какой файл будет ведения дубликат группы. dupeGuru предполагает, что вы всегда хотите сохранить крупнейших файл, так что крупных файлов займет исходное положение. + +Вы можете изменить ссылку файл группы вручную. Для этого выберите дубликат файла, который вы хотите продвигать на ссылку, и нажмите на кнопку **Действия -> Добавить выбранной ссылки**. + +Просмотр результатов +-------------------- + +Хотя вы можете просто нажать на **Правка -> Выделить все, а затем** **Действия -> Отправить Помечено в Корзину** быстро удалить все дубликаты файлов в результатах, всегда рекомендуется пересмотреть все дубликаты перед удаляя их. + +Чтобы помочь вам обзор результатов, вы можете вызвать панель **Подробнее**. Эта панель показывает все детали выбранного файла, а также подробности своей ссылки в. Это очень удобно, чтобы быстро определить, если дубликат действительно дубликат. Вы также можете дважды щелкнуть по файлу, чтобы открыть его и связанные с ним приложения. + +Если у вас есть больше ложных дубликатов, чем правда дубликатов (Если Ваш фильтр жесткость очень низкая), лучший способ продолжить бы пересмотреть дубликатов, знак истинного дубликаты и нажмите **Действия -> Отправить Помечено в Корзину** . Если у вас есть более верно, чем ложных дубликатов дубликатов, вместо этого можно пометить все файлы, которые являются ложными дубликатов, а также использовать **Действия -> Удалить Помеченные от результатов**. + +Маркировка и выбор +--------------------- + +**Отмеченные** дубликат двух экземплярах с небольшой флажок рядом с ним, имеющие галочки. **Выбран дубликат дубликата** быть выделены. Несколько действий, выбор может быть выполнена в dupeGuru стандартным образом (Shift / Command / Control клик). Вы можете переключать знак состояние всех выбранных дубликаты ", нажав **пространстве**. + +Показать только обманутые +------------------------- + +Когда этот режим включен, дубликаты отображаются без их соответствующего файла справки. Вы можете выбрать, марка и сортировать этот список, как и в обычном режиме. + +DupeGuru результаты, когда в нормальном режиме, сортируются в соответствии с дубликат группы '**ссылке на файл**. Это означает, что если вы хотите, например, чтобы отметить все дубликаты "EXE" расширением, вы не можете просто сортировать результаты по "Вид", чтобы иметь все EXE дубликатов вместе, потому что группа может состоять из более чем одного типа файлов . Вот где обманутые Только режим вступает в игру. Чтобы отметить все ваши "EXE" дубликаты, вы просто должны: + +* Включить обманутые Только режим. +* Добавить "Вид" колонку "Столбцы" меню. +* Нажмите на том, что "Вид" колонки, чтобы отсортировать список по типу. +* Найдите первый дубликат с "EXE" рода. +* Выберите его. +* Прокрутите список, чтобы найти последнего дубликата с "EXE" рода. +* Удерживайте Shift и щелкните по нему. +* Нажмите Space, чтобы пометить все выбранные дубликатов. + +Дельта значения +--------------- + +Если включить этот переключатель на некоторые столбцы будут отображать значение по отношению к дубликата ссылке, а не абсолютные значения. Эти дельты значения также будут отображаться в разные цвета, чтобы вы могли заметить их легко. Например, если дубликат 1,2 Мб и свою ссылку в 1,4 Мб, размер столбец отображает -0,2 Мб. + +Только обманутые и Дельта значения +---------------------------------- + +Только обманутые режиме раскрыть свою истинную силу, когда вы используете его с Делта Значения переключатель включен. Когда вы включите его, относительные значения будет отображаться вместо абсолютных. Так что если, например, вы хотите удалить из результатов все дубликаты, которые являются более 300 Кб от их ссылке, вы можете отсортировать дубликаты только результаты по размеру, выберите все дубликаты при -300 в столбце Размер, удалять их, , а затем сделать то же самое повторяет более 300 в нижней части списка. + +Вы можете также использовать его для изменения ссылки приоритет повторяющиеся список. Когда вы делаете свежие сканирования, если Есть нет ссылки папки, ссылке на файл каждой группы является самой большой файл. Если вы хотите изменить, что, например, в последней модификации время, вы можете отсортировать дубликаты только результаты по времени модификации в **убывания** порядке выберите все дубликаты со временем изменения дельты значение больше 0 и нажмите **Убедитесь, выбранной ссылки**. Причина, почему вы должны сделать порядок сортировки по убыванию, потому что если 2 файла среди таких же дубликат группы выбираются при нажатии на **Сделать выбранной ссылки**, только первый из списка будут сделаны ссылки, другие будут проигнорированы . И так как вы хотите Последнее изменение файла для ссылки, имеющие порядок сортировки по убыванию уверяет вас, что первым пунктом в списке будет последнего изменения. + +.. todo:: Add "Non-numerical delta" information. + +Фильтрация +---------- + +dupeGuru поддерживает после сканирования, фильтрации. С его помощью вы можете сузить результаты, чтобы вы могли выполнять действия, на подмножества. Например, вы можете легко пометить все дубликаты с их имя файла, содержащего "копировать" из результатов с помощью фильтра. + +.. todo:: Qt has a toolbar search field now, not a menu item. + +**Windows:** Для использования функции фильтрации, нажмите на Действия -> Применить фильтр, запишите фильтр, который вы хотите применить и нажмите ОК. Чтобы вернуться к нефильтрованное результаты, нажмите на Действия -> Отменить фильтр. + +**Mac OS X:** Для использования функции фильтрации, тип фильтра в "Фильтр" поле поиска на панели инструментов. Чтобы вернуться к нефильтрованное результате, очистите поле, или нажмите на кнопку "X". + +В простом режиме (режим по умолчанию), что вы вводите в качестве фильтра строку, используемую для выполнения фактической фильтрации, за исключением одной маски: **\***. Таким образом, если вы введете "[*]" как ваш фильтр, он будет соответствовать что-нибудь с [] скобках в нем, все, что между этими скобками. + +Для более продвинутых фильтров, вы можете включить «Использование регулярных выражений при фильтрации" на. Функция фильтрации будет использовать регулярные выражения. Регулярное выражение языка для согласования текста. Объясняя их выходит за рамки этого документа. Хорошее место для начала обучения он `regular_expressions.info` _. + +Матчи не чувствительны к регистру, в простых и регулярных выражений режиме. + +Для фильтра, чтобы соответствовать, регулярное выражение не обязательно должно совпадать целый файл, он просто обязан содержать в цепочку, соответствующую выражению. + +Вы могли заметить, что не все дубликаты в результате будут соответствовать вашим фильтром. Это потому, что как только одна копия в матчах группового фильтра, то вся группа останется в результатах, таким образом Вы можете иметь более четкое представление о дубликата контексте. Тем не менее, не соответствующие дубликаты в "ссылку режиме". Таким образом, можно выполнять действия, как Марк все и обязательно только знак фильтруется дубликатов. + +Действие меню +------------- + +* **Открытый черный список:** Удалите все игнорируют матчи вы добавили. Вы должны начать новый поиск вновь очищается список игнорируемых чтобы быть эффективными. +* **Экспорт результатов в XHTML:** Возьмите текущие результаты, а также создавать файл XHTML из него. Столбцов, которые видны при нажатии на эту кнопку будет столбцов в файле XHTML. Файл автоматически откроется в браузере по умолчанию. +* **Отправить Помечено в корзину:** Отправить все отмеченные дубликаты, мусор, это очевидно. +* **Удалить Помеченные и замена с Жесткие**: Передает все отмеченные дубликаты, мусор, но после того, как сделали это, удаленные файлы заменяются `жестких `_ ссылку к ссылке на файл. (Только для OS X и Linux) +* **Перемещение Помечено в ...:** запросит назначения, а затем переместить все отмеченные файлы в том, что назначения. Путь исходного файла может быть воссоздан в пункт назначения, в зависимости от "Копирование и перемещение" предпочтения. +* **Скопируйте Помечено в ...:** запросит у вас место, а затем скопировать все выбранные файлы к этому пункту назначения. Путь исходного файла может быть воссоздан в пункт назначения, в зависимости от "Копирование и перемещение" предпочтения. +* **Удалить Помеченные из результатов:** Удалить все отмеченные дубликатов из результата поиска. Сами файлы не будут затронуты и останутся, где они. +* **Удалить выбранные из результатов:** Удалить все выбранные дубликатов из результата поиска. Обратите внимание, что все выбранные файлы ссылки будут игнорироваться, только дубликаты могут быть удалены с этим действием. +* **Сделать Выбранный Справка:** Содействие все выбранные дубликатов ссылки. Если дубликат частью группы, имеющей ссылке на файл ближайшие из ссылки папки (в синий цвет), не будут приняты меры для этого дубликат. Если более чем один дубликат среди той же группы выбраны, только первый из каждой группы будет поощряться. +* **Добавить выбранные в черный список:** Это сначала удаляет все выбранные дубликаты из результатов, а затем добавить матча, которые дублируют и опорный ток в черный список. Этот матч не придет снова в дальнейшей проверки. Копировать себя и, возможно, вернется, но он будет искаться в другой ссылке на файл. Вы можете очистить список игнорируемых с Открытый черный список команды. +* **Открытое Выбранный с приложений по умолчанию:** Откройте файл с помощью приложения, связанного с типом выбранного файла. +* **Показать Выбранный в Finder-е:** Откройте папку, содержащую выбранный файл. +* **Вызов специальной команды:** Вызывает внешнюю программу вы установили в настройках с использованием выделенного фрагмента в качестве аргументов в вызове. +* **Переименования выбрано:** Запрашивает новое имя, а затем переименовать выбранный файл. + +.. todo:: Add Move and iPhoto/iTunes warning +.. todo:: Add "Deletion Options" section. \ No newline at end of file diff --git a/help/ru/_static/_stemmer.js b/help/ru/_static/_stemmer.js new file mode 100644 index 00000000..74d63096 --- /dev/null +++ b/help/ru/_static/_stemmer.js @@ -0,0 +1,2232 @@ +// generatedy by JSX compiler 0.9.89 (2014-05-20 06:01:03 +0900; 8e8c6105f36f3dfe440ea026a3c93a3444977102) +var JSX = {}; +(function (JSX) { +/** + * extends the class + */ +function $__jsx_extend(derivations, base) { + var ctor = function () {}; + ctor.prototype = base.prototype; + var proto = new ctor(); + for (var i in derivations) { + derivations[i].prototype = proto; + } +} + +/** + * copies the implementations from source interface to target + */ +function $__jsx_merge_interface(target, source) { + for (var k in source.prototype) + if (source.prototype.hasOwnProperty(k)) + target.prototype[k] = source.prototype[k]; +} + +/** + * defers the initialization of the property + */ +function $__jsx_lazy_init(obj, prop, func) { + function reset(obj, prop, value) { + delete obj[prop]; + obj[prop] = value; + return value; + } + + Object.defineProperty(obj, prop, { + get: function () { + return reset(obj, prop, func()); + }, + set: function (v) { + reset(obj, prop, v); + }, + enumerable: true, + configurable: true + }); +} + +var $__jsx_imul = Math.imul; +if (typeof $__jsx_imul === "undefined") { + $__jsx_imul = function (a, b) { + var ah = (a >>> 16) & 0xffff; + var al = a & 0xffff; + var bh = (b >>> 16) & 0xffff; + var bl = b & 0xffff; + return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0); + }; +} + +/** + * fused int-ops with side-effects + */ +function $__jsx_ipadd(o, p, r) { + return o[p] = (o[p] + r) | 0; +} +function $__jsx_ipsub(o, p, r) { + return o[p] = (o[p] - r) | 0; +} +function $__jsx_ipmul(o, p, r) { + return o[p] = $__jsx_imul(o[p], r); +} +function $__jsx_ipdiv(o, p, r) { + return o[p] = (o[p] / r) | 0; +} +function $__jsx_ipmod(o, p, r) { + return o[p] = (o[p] % r) | 0; +} +function $__jsx_ippostinc(o, p) { + var v = o[p]; + o[p] = (v + 1) | 0; + return v; +} +function $__jsx_ippostdec(o, p) { + var v = o[p]; + o[p] = (v - 1) | 0; + return v; +} + +/** + * non-inlined version of Array#each + */ +function $__jsx_forEach(o, f) { + var l = o.length; + for (var i = 0; i < l; ++i) + f(o[i]); +} + +/* + * global functions, renamed to avoid conflict with local variable names + */ +var $__jsx_parseInt = parseInt; +var $__jsx_parseFloat = parseFloat; +function $__jsx_isNaN(n) { return n !== n; } +var $__jsx_isFinite = isFinite; + +var $__jsx_encodeURIComponent = encodeURIComponent; +var $__jsx_decodeURIComponent = decodeURIComponent; +var $__jsx_encodeURI = encodeURI; +var $__jsx_decodeURI = decodeURI; + +var $__jsx_ObjectToString = Object.prototype.toString; +var $__jsx_ObjectHasOwnProperty = Object.prototype.hasOwnProperty; + +/* + * profiler object, initialized afterwards + */ +function $__jsx_profiler() { +} + +/* + * public interface to JSX code + */ +JSX.require = function (path) { + var m = $__jsx_classMap[path]; + return m !== undefined ? m : null; +}; + +JSX.profilerIsRunning = function () { + return $__jsx_profiler.getResults != null; +}; + +JSX.getProfileResults = function () { + return ($__jsx_profiler.getResults || function () { return {}; })(); +}; + +JSX.postProfileResults = function (url, cb) { + if ($__jsx_profiler.postResults == null) + throw new Error("profiler has not been turned on"); + return $__jsx_profiler.postResults(url, cb); +}; + +JSX.resetProfileResults = function () { + if ($__jsx_profiler.resetResults == null) + throw new Error("profiler has not been turned on"); + return $__jsx_profiler.resetResults(); +}; +JSX.DEBUG = false; +var GeneratorFunction$0 = +(function () { + try { + return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); + } catch (e) { + return function GeneratorFunction () {}; + } +})(); +var __jsx_generator_object$0 = +(function () { + function __jsx_generator_object() { + this.__next = 0; + this.__loop = null; + this.__seed = null; + this.__value = undefined; + this.__status = 0; // SUSPENDED: 0, ACTIVE: 1, DEAD: 2 + } + + __jsx_generator_object.prototype.next = function (seed) { + switch (this.__status) { + case 0: + this.__status = 1; + this.__seed = seed; + + // go next! + this.__loop(this.__next); + + var done = false; + if (this.__next != -1) { + this.__status = 0; + } else { + this.__status = 2; + done = true; + } + return { value: this.__value, done: done }; + case 1: + throw new Error("Generator is already running"); + case 2: + throw new Error("Generator is already finished"); + default: + throw new Error("Unexpected generator internal state"); + } + }; + + return __jsx_generator_object; +}()); +function Among(s, substring_i, result) { + this.s_size = s.length; + this.s = s; + this.substring_i = substring_i; + this.result = result; + this.method = null; + this.instance = null; +}; + +function Among$0(s, substring_i, result, method, instance) { + this.s_size = s.length; + this.s = s; + this.substring_i = substring_i; + this.result = result; + this.method = method; + this.instance = instance; +}; + +$__jsx_extend([Among, Among$0], Object); +function Stemmer() { +}; + +$__jsx_extend([Stemmer], Object); +function BaseStemmer() { + var current$0; + var cursor$0; + var limit$0; + this.cache = ({ }); + current$0 = this.current = ""; + cursor$0 = this.cursor = 0; + limit$0 = this.limit = current$0.length; + this.limit_backward = 0; + this.bra = cursor$0; + this.ket = limit$0; +}; + +$__jsx_extend([BaseStemmer], Stemmer); +BaseStemmer.prototype.setCurrent$S = function (value) { + var current$0; + var cursor$0; + var limit$0; + current$0 = this.current = value; + cursor$0 = this.cursor = 0; + limit$0 = this.limit = current$0.length; + this.limit_backward = 0; + this.bra = cursor$0; + this.ket = limit$0; +}; + + +function BaseStemmer$setCurrent$LBaseStemmer$S($this, value) { + var current$0; + var cursor$0; + var limit$0; + current$0 = $this.current = value; + cursor$0 = $this.cursor = 0; + limit$0 = $this.limit = current$0.length; + $this.limit_backward = 0; + $this.bra = cursor$0; + $this.ket = limit$0; +}; + +BaseStemmer.setCurrent$LBaseStemmer$S = BaseStemmer$setCurrent$LBaseStemmer$S; + +BaseStemmer.prototype.getCurrent$ = function () { + return this.current; +}; + + +function BaseStemmer$getCurrent$LBaseStemmer$($this) { + return $this.current; +}; + +BaseStemmer.getCurrent$LBaseStemmer$ = BaseStemmer$getCurrent$LBaseStemmer$; + +BaseStemmer.prototype.copy_from$LBaseStemmer$ = function (other) { + this.current = other.current; + this.cursor = other.cursor; + this.limit = other.limit; + this.limit_backward = other.limit_backward; + this.bra = other.bra; + this.ket = other.ket; +}; + + +function BaseStemmer$copy_from$LBaseStemmer$LBaseStemmer$($this, other) { + $this.current = other.current; + $this.cursor = other.cursor; + $this.limit = other.limit; + $this.limit_backward = other.limit_backward; + $this.bra = other.bra; + $this.ket = other.ket; +}; + +BaseStemmer.copy_from$LBaseStemmer$LBaseStemmer$ = BaseStemmer$copy_from$LBaseStemmer$LBaseStemmer$; + +BaseStemmer.prototype.in_grouping$AIII = function (s, min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor >= this.limit) { + return false; + } + ch = this.current.charCodeAt(this.cursor); + if (ch > max || ch < min) { + return false; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$in_grouping$LBaseStemmer$AIII($this, s, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor >= $this.limit) { + return false; + } + ch = $this.current.charCodeAt($this.cursor); + if (ch > max || ch < min) { + return false; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.in_grouping$LBaseStemmer$AIII = BaseStemmer$in_grouping$LBaseStemmer$AIII; + +BaseStemmer.prototype.in_grouping_b$AIII = function (s, min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor <= this.limit_backward) { + return false; + } + ch = this.current.charCodeAt(this.cursor - 1); + if (ch > max || ch < min) { + return false; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$in_grouping_b$LBaseStemmer$AIII($this, s, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor <= $this.limit_backward) { + return false; + } + ch = $this.current.charCodeAt($this.cursor - 1); + if (ch > max || ch < min) { + return false; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.in_grouping_b$LBaseStemmer$AIII = BaseStemmer$in_grouping_b$LBaseStemmer$AIII; + +BaseStemmer.prototype.out_grouping$AIII = function (s, min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor >= this.limit) { + return false; + } + ch = this.current.charCodeAt(this.cursor); + if (ch > max || ch < min) { + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; + } + ch -= min; + if ((s[ch >>> 3] & 0X1 << (ch & 0x7)) === 0) { + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; + } + return false; +}; + + +function BaseStemmer$out_grouping$LBaseStemmer$AIII($this, s, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor >= $this.limit) { + return false; + } + ch = $this.current.charCodeAt($this.cursor); + if (ch > max || ch < min) { + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; + } + ch -= min; + if ((s[ch >>> 3] & 0X1 << (ch & 0x7)) === 0) { + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; + } + return false; +}; + +BaseStemmer.out_grouping$LBaseStemmer$AIII = BaseStemmer$out_grouping$LBaseStemmer$AIII; + +BaseStemmer.prototype.out_grouping_b$AIII = function (s, min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor <= this.limit_backward) { + return false; + } + ch = this.current.charCodeAt(this.cursor - 1); + if (ch > max || ch < min) { + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; + } + return false; +}; + + +function BaseStemmer$out_grouping_b$LBaseStemmer$AIII($this, s, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor <= $this.limit_backward) { + return false; + } + ch = $this.current.charCodeAt($this.cursor - 1); + if (ch > max || ch < min) { + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; + } + ch -= min; + if ((s[ch >>> 3] & 0x1 << (ch & 0x7)) === 0) { + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; + } + return false; +}; + +BaseStemmer.out_grouping_b$LBaseStemmer$AIII = BaseStemmer$out_grouping_b$LBaseStemmer$AIII; + +BaseStemmer.prototype.in_range$II = function (min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor >= this.limit) { + return false; + } + ch = this.current.charCodeAt(this.cursor); + if (ch > max || ch < min) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$in_range$LBaseStemmer$II($this, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor >= $this.limit) { + return false; + } + ch = $this.current.charCodeAt($this.cursor); + if (ch > max || ch < min) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.in_range$LBaseStemmer$II = BaseStemmer$in_range$LBaseStemmer$II; + +BaseStemmer.prototype.in_range_b$II = function (min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor <= this.limit_backward) { + return false; + } + ch = this.current.charCodeAt(this.cursor - 1); + if (ch > max || ch < min) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$in_range_b$LBaseStemmer$II($this, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor <= $this.limit_backward) { + return false; + } + ch = $this.current.charCodeAt($this.cursor - 1); + if (ch > max || ch < min) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.in_range_b$LBaseStemmer$II = BaseStemmer$in_range_b$LBaseStemmer$II; + +BaseStemmer.prototype.out_range$II = function (min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor >= this.limit) { + return false; + } + ch = this.current.charCodeAt(this.cursor); + if (! (ch > max || ch < min)) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$out_range$LBaseStemmer$II($this, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor >= $this.limit) { + return false; + } + ch = $this.current.charCodeAt($this.cursor); + if (! (ch > max || ch < min)) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.out_range$LBaseStemmer$II = BaseStemmer$out_range$LBaseStemmer$II; + +BaseStemmer.prototype.out_range_b$II = function (min, max) { + var ch; + var $__jsx_postinc_t; + if (this.cursor <= this.limit_backward) { + return false; + } + ch = this.current.charCodeAt(this.cursor - 1); + if (! (ch > max || ch < min)) { + return false; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + + +function BaseStemmer$out_range_b$LBaseStemmer$II($this, min, max) { + var ch; + var $__jsx_postinc_t; + if ($this.cursor <= $this.limit_backward) { + return false; + } + ch = $this.current.charCodeAt($this.cursor - 1); + if (! (ch > max || ch < min)) { + return false; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t - 1) | 0, $__jsx_postinc_t); + return true; +}; + +BaseStemmer.out_range_b$LBaseStemmer$II = BaseStemmer$out_range_b$LBaseStemmer$II; + +BaseStemmer.prototype.eq_s$IS = function (s_size, s) { + var cursor$0; + if (((this.limit - this.cursor) | 0) < s_size) { + return false; + } + if (this.current.slice(cursor$0 = this.cursor, ((cursor$0 + s_size) | 0)) !== s) { + return false; + } + this.cursor = (this.cursor + s_size) | 0; + return true; +}; + + +function BaseStemmer$eq_s$LBaseStemmer$IS($this, s_size, s) { + var cursor$0; + if ((($this.limit - $this.cursor) | 0) < s_size) { + return false; + } + if ($this.current.slice(cursor$0 = $this.cursor, ((cursor$0 + s_size) | 0)) !== s) { + return false; + } + $this.cursor = ($this.cursor + s_size) | 0; + return true; +}; + +BaseStemmer.eq_s$LBaseStemmer$IS = BaseStemmer$eq_s$LBaseStemmer$IS; + +BaseStemmer.prototype.eq_s_b$IS = function (s_size, s) { + var cursor$0; + if (((this.cursor - this.limit_backward) | 0) < s_size) { + return false; + } + if (this.current.slice((((cursor$0 = this.cursor) - s_size) | 0), cursor$0) !== s) { + return false; + } + this.cursor = (this.cursor - s_size) | 0; + return true; +}; + + +function BaseStemmer$eq_s_b$LBaseStemmer$IS($this, s_size, s) { + var cursor$0; + if ((($this.cursor - $this.limit_backward) | 0) < s_size) { + return false; + } + if ($this.current.slice((((cursor$0 = $this.cursor) - s_size) | 0), cursor$0) !== s) { + return false; + } + $this.cursor = ($this.cursor - s_size) | 0; + return true; +}; + +BaseStemmer.eq_s_b$LBaseStemmer$IS = BaseStemmer$eq_s_b$LBaseStemmer$IS; + +BaseStemmer.prototype.eq_v$S = function (s) { + return BaseStemmer$eq_s$LBaseStemmer$IS(this, s.length, s); +}; + + +function BaseStemmer$eq_v$LBaseStemmer$S($this, s) { + return BaseStemmer$eq_s$LBaseStemmer$IS($this, s.length, s); +}; + +BaseStemmer.eq_v$LBaseStemmer$S = BaseStemmer$eq_v$LBaseStemmer$S; + +BaseStemmer.prototype.eq_v_b$S = function (s) { + return BaseStemmer$eq_s_b$LBaseStemmer$IS(this, s.length, s); +}; + + +function BaseStemmer$eq_v_b$LBaseStemmer$S($this, s) { + return BaseStemmer$eq_s_b$LBaseStemmer$IS($this, s.length, s); +}; + +BaseStemmer.eq_v_b$LBaseStemmer$S = BaseStemmer$eq_v_b$LBaseStemmer$S; + +BaseStemmer.prototype.find_among$ALAmong$I = function (v, v_size) { + var i; + var j; + var c; + var l; + var common_i; + var common_j; + var first_key_inspected; + var k; + var diff; + var common; + var w; + var i2; + var res; + i = 0; + j = v_size; + c = this.cursor; + l = this.limit; + common_i = 0; + common_j = 0; + first_key_inspected = false; + while (true) { + k = i + (j - i >>> 1); + diff = 0; + common = (common_i < common_j ? common_i : common_j); + w = v[k]; + for (i2 = common; i2 < w.s_size; i2++) { + if (c + common === l) { + diff = -1; + break; + } + diff = this.current.charCodeAt(c + common) - w.s.charCodeAt(i2); + if (diff !== 0) { + break; + } + common++; + } + if (diff < 0) { + j = k; + common_j = common; + } else { + i = k; + common_i = common; + } + if (j - i <= 1) { + if (i > 0) { + break; + } + if (j === i) { + break; + } + if (first_key_inspected) { + break; + } + first_key_inspected = true; + } + } + while (true) { + w = v[i]; + if (common_i >= w.s_size) { + this.cursor = (c + w.s_size | 0); + if (w.method == null) { + return w.result; + } + res = w.method(w.instance); + this.cursor = (c + w.s_size | 0); + if (res) { + return w.result; + } + } + i = w.substring_i; + if (i < 0) { + return 0; + } + } + return -1; +}; + + +function BaseStemmer$find_among$LBaseStemmer$ALAmong$I($this, v, v_size) { + var i; + var j; + var c; + var l; + var common_i; + var common_j; + var first_key_inspected; + var k; + var diff; + var common; + var w; + var i2; + var res; + i = 0; + j = v_size; + c = $this.cursor; + l = $this.limit; + common_i = 0; + common_j = 0; + first_key_inspected = false; + while (true) { + k = i + (j - i >>> 1); + diff = 0; + common = (common_i < common_j ? common_i : common_j); + w = v[k]; + for (i2 = common; i2 < w.s_size; i2++) { + if (c + common === l) { + diff = -1; + break; + } + diff = $this.current.charCodeAt(c + common) - w.s.charCodeAt(i2); + if (diff !== 0) { + break; + } + common++; + } + if (diff < 0) { + j = k; + common_j = common; + } else { + i = k; + common_i = common; + } + if (j - i <= 1) { + if (i > 0) { + break; + } + if (j === i) { + break; + } + if (first_key_inspected) { + break; + } + first_key_inspected = true; + } + } + while (true) { + w = v[i]; + if (common_i >= w.s_size) { + $this.cursor = (c + w.s_size | 0); + if (w.method == null) { + return w.result; + } + res = w.method(w.instance); + $this.cursor = (c + w.s_size | 0); + if (res) { + return w.result; + } + } + i = w.substring_i; + if (i < 0) { + return 0; + } + } + return -1; +}; + +BaseStemmer.find_among$LBaseStemmer$ALAmong$I = BaseStemmer$find_among$LBaseStemmer$ALAmong$I; + +BaseStemmer.prototype.find_among_b$ALAmong$I = function (v, v_size) { + var i; + var j; + var c; + var lb; + var common_i; + var common_j; + var first_key_inspected; + var k; + var diff; + var common; + var w; + var i2; + var res; + i = 0; + j = v_size; + c = this.cursor; + lb = this.limit_backward; + common_i = 0; + common_j = 0; + first_key_inspected = false; + while (true) { + k = i + (j - i >> 1); + diff = 0; + common = (common_i < common_j ? common_i : common_j); + w = v[k]; + for (i2 = w.s_size - 1 - common; i2 >= 0; i2--) { + if (c - common === lb) { + diff = -1; + break; + } + diff = this.current.charCodeAt(c - 1 - common) - w.s.charCodeAt(i2); + if (diff !== 0) { + break; + } + common++; + } + if (diff < 0) { + j = k; + common_j = common; + } else { + i = k; + common_i = common; + } + if (j - i <= 1) { + if (i > 0) { + break; + } + if (j === i) { + break; + } + if (first_key_inspected) { + break; + } + first_key_inspected = true; + } + } + while (true) { + w = v[i]; + if (common_i >= w.s_size) { + this.cursor = (c - w.s_size | 0); + if (w.method == null) { + return w.result; + } + res = w.method(this); + this.cursor = (c - w.s_size | 0); + if (res) { + return w.result; + } + } + i = w.substring_i; + if (i < 0) { + return 0; + } + } + return -1; +}; + + +function BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, v, v_size) { + var i; + var j; + var c; + var lb; + var common_i; + var common_j; + var first_key_inspected; + var k; + var diff; + var common; + var w; + var i2; + var res; + i = 0; + j = v_size; + c = $this.cursor; + lb = $this.limit_backward; + common_i = 0; + common_j = 0; + first_key_inspected = false; + while (true) { + k = i + (j - i >> 1); + diff = 0; + common = (common_i < common_j ? common_i : common_j); + w = v[k]; + for (i2 = w.s_size - 1 - common; i2 >= 0; i2--) { + if (c - common === lb) { + diff = -1; + break; + } + diff = $this.current.charCodeAt(c - 1 - common) - w.s.charCodeAt(i2); + if (diff !== 0) { + break; + } + common++; + } + if (diff < 0) { + j = k; + common_j = common; + } else { + i = k; + common_i = common; + } + if (j - i <= 1) { + if (i > 0) { + break; + } + if (j === i) { + break; + } + if (first_key_inspected) { + break; + } + first_key_inspected = true; + } + } + while (true) { + w = v[i]; + if (common_i >= w.s_size) { + $this.cursor = (c - w.s_size | 0); + if (w.method == null) { + return w.result; + } + res = w.method($this); + $this.cursor = (c - w.s_size | 0); + if (res) { + return w.result; + } + } + i = w.substring_i; + if (i < 0) { + return 0; + } + } + return -1; +}; + +BaseStemmer.find_among_b$LBaseStemmer$ALAmong$I = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I; + +BaseStemmer.prototype.replace_s$IIS = function (c_bra, c_ket, s) { + var adjustment; + adjustment = ((s.length - (((c_ket - c_bra) | 0))) | 0); + this.current = this.current.slice(0, c_bra) + s + this.current.slice(c_ket); + this.limit = (this.limit + adjustment) | 0; + if (this.cursor >= c_ket) { + this.cursor = (this.cursor + adjustment) | 0; + } else if (this.cursor > c_bra) { + this.cursor = c_bra; + } + return (adjustment | 0); +}; + + +function BaseStemmer$replace_s$LBaseStemmer$IIS($this, c_bra, c_ket, s) { + var adjustment; + adjustment = ((s.length - (((c_ket - c_bra) | 0))) | 0); + $this.current = $this.current.slice(0, c_bra) + s + $this.current.slice(c_ket); + $this.limit = ($this.limit + adjustment) | 0; + if ($this.cursor >= c_ket) { + $this.cursor = ($this.cursor + adjustment) | 0; + } else if ($this.cursor > c_bra) { + $this.cursor = c_bra; + } + return (adjustment | 0); +}; + +BaseStemmer.replace_s$LBaseStemmer$IIS = BaseStemmer$replace_s$LBaseStemmer$IIS; + +BaseStemmer.prototype.slice_check$ = function () { + var bra$0; + var ket$0; + var limit$0; + return ((bra$0 = this.bra) < 0 || bra$0 > (ket$0 = this.ket) || ket$0 > (limit$0 = this.limit) || limit$0 > this.current.length ? false : true); +}; + + +function BaseStemmer$slice_check$LBaseStemmer$($this) { + var bra$0; + var ket$0; + var limit$0; + return ((bra$0 = $this.bra) < 0 || bra$0 > (ket$0 = $this.ket) || ket$0 > (limit$0 = $this.limit) || limit$0 > $this.current.length ? false : true); +}; + +BaseStemmer.slice_check$LBaseStemmer$ = BaseStemmer$slice_check$LBaseStemmer$; + +BaseStemmer.prototype.slice_from$S = function (s) { + var result; + var bra$0; + var ket$0; + var limit$0; + result = false; + if ((bra$0 = this.bra) < 0 || bra$0 > (ket$0 = this.ket) || ket$0 > (limit$0 = this.limit) || limit$0 > this.current.length ? false : true) { + BaseStemmer$replace_s$LBaseStemmer$IIS(this, this.bra, this.ket, s); + result = true; + } + return result; +}; + + +function BaseStemmer$slice_from$LBaseStemmer$S($this, s) { + var result; + var bra$0; + var ket$0; + var limit$0; + result = false; + if ((bra$0 = $this.bra) < 0 || bra$0 > (ket$0 = $this.ket) || ket$0 > (limit$0 = $this.limit) || limit$0 > $this.current.length ? false : true) { + BaseStemmer$replace_s$LBaseStemmer$IIS($this, $this.bra, $this.ket, s); + result = true; + } + return result; +}; + +BaseStemmer.slice_from$LBaseStemmer$S = BaseStemmer$slice_from$LBaseStemmer$S; + +BaseStemmer.prototype.slice_del$ = function () { + return BaseStemmer$slice_from$LBaseStemmer$S(this, ""); +}; + + +function BaseStemmer$slice_del$LBaseStemmer$($this) { + return BaseStemmer$slice_from$LBaseStemmer$S($this, ""); +}; + +BaseStemmer.slice_del$LBaseStemmer$ = BaseStemmer$slice_del$LBaseStemmer$; + +BaseStemmer.prototype.insert$IIS = function (c_bra, c_ket, s) { + var adjustment; + adjustment = BaseStemmer$replace_s$LBaseStemmer$IIS(this, c_bra, c_ket, s); + if (c_bra <= this.bra) { + this.bra = (this.bra + adjustment) | 0; + } + if (c_bra <= this.ket) { + this.ket = (this.ket + adjustment) | 0; + } +}; + + +function BaseStemmer$insert$LBaseStemmer$IIS($this, c_bra, c_ket, s) { + var adjustment; + adjustment = BaseStemmer$replace_s$LBaseStemmer$IIS($this, c_bra, c_ket, s); + if (c_bra <= $this.bra) { + $this.bra = ($this.bra + adjustment) | 0; + } + if (c_bra <= $this.ket) { + $this.ket = ($this.ket + adjustment) | 0; + } +}; + +BaseStemmer.insert$LBaseStemmer$IIS = BaseStemmer$insert$LBaseStemmer$IIS; + +BaseStemmer.prototype.slice_to$S = function (s) { + var result; + var bra$0; + var ket$0; + var limit$0; + result = ''; + if ((bra$0 = this.bra) < 0 || bra$0 > (ket$0 = this.ket) || ket$0 > (limit$0 = this.limit) || limit$0 > this.current.length ? false : true) { + result = this.current.slice(this.bra, this.ket); + } + return result; +}; + + +function BaseStemmer$slice_to$LBaseStemmer$S($this, s) { + var result; + var bra$0; + var ket$0; + var limit$0; + result = ''; + if ((bra$0 = $this.bra) < 0 || bra$0 > (ket$0 = $this.ket) || ket$0 > (limit$0 = $this.limit) || limit$0 > $this.current.length ? false : true) { + result = $this.current.slice($this.bra, $this.ket); + } + return result; +}; + +BaseStemmer.slice_to$LBaseStemmer$S = BaseStemmer$slice_to$LBaseStemmer$S; + +BaseStemmer.prototype.assign_to$S = function (s) { + return this.current.slice(0, this.limit); +}; + + +function BaseStemmer$assign_to$LBaseStemmer$S($this, s) { + return $this.current.slice(0, $this.limit); +}; + +BaseStemmer.assign_to$LBaseStemmer$S = BaseStemmer$assign_to$LBaseStemmer$S; + +BaseStemmer.prototype.stem$ = function () { + return false; +}; + + +BaseStemmer.prototype.stemWord$S = function (word) { + var result; + var current$0; + var cursor$0; + var limit$0; + result = this.cache['.' + word]; + if (result == null) { + current$0 = this.current = word; + cursor$0 = this.cursor = 0; + limit$0 = this.limit = current$0.length; + this.limit_backward = 0; + this.bra = cursor$0; + this.ket = limit$0; + this.stem$(); + result = this.current; + this.cache['.' + word] = result; + } + return result; +}; + +BaseStemmer.prototype.stemWord = BaseStemmer.prototype.stemWord$S; + +BaseStemmer.prototype.stemWords$AS = function (words) { + var results; + var i; + var word; + var result; + var current$0; + var cursor$0; + var limit$0; + results = [ ]; + for (i = 0; i < words.length; i++) { + word = words[i]; + result = this.cache['.' + word]; + if (result == null) { + current$0 = this.current = word; + cursor$0 = this.cursor = 0; + limit$0 = this.limit = current$0.length; + this.limit_backward = 0; + this.bra = cursor$0; + this.ket = limit$0; + this.stem$(); + result = this.current; + this.cache['.' + word] = result; + } + results.push(result); + } + return results; +}; + +BaseStemmer.prototype.stemWords = BaseStemmer.prototype.stemWords$AS; + +function RussianStemmer() { + BaseStemmer.call(this); + this.I_p2 = 0; + this.I_pV = 0; +}; + +$__jsx_extend([RussianStemmer], BaseStemmer); +RussianStemmer.prototype.copy_from$LRussianStemmer$ = function (other) { + this.I_p2 = other.I_p2; + this.I_pV = other.I_pV; + BaseStemmer$copy_from$LBaseStemmer$LBaseStemmer$(this, other); +}; + +RussianStemmer.prototype.copy_from = RussianStemmer.prototype.copy_from$LRussianStemmer$; + +RussianStemmer.prototype.r_mark_regions$ = function () { + var v_1; + var lab0; + var lab2; + var lab4; + var lab6; + var lab8; + var limit$0; + var $__jsx_postinc_t; + this.I_pV = limit$0 = this.limit; + this.I_p2 = limit$0; + v_1 = this.cursor; + lab0 = true; +lab0: + while (lab0 === true) { + lab0 = false; + golab1: + while (true) { + lab2 = true; + lab2: + while (lab2 === true) { + lab2 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, RussianStemmer.g_v, 1072, 1103)) { + break lab2; + } + break golab1; + } + if (this.cursor >= this.limit) { + break lab0; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + this.I_pV = this.cursor; + golab3: + while (true) { + lab4 = true; + lab4: + while (lab4 === true) { + lab4 = false; + if (! BaseStemmer$out_grouping$LBaseStemmer$AIII(this, RussianStemmer.g_v, 1072, 1103)) { + break lab4; + } + break golab3; + } + if (this.cursor >= this.limit) { + break lab0; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + golab5: + while (true) { + lab6 = true; + lab6: + while (lab6 === true) { + lab6 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII(this, RussianStemmer.g_v, 1072, 1103)) { + break lab6; + } + break golab5; + } + if (this.cursor >= this.limit) { + break lab0; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + golab7: + while (true) { + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + if (! BaseStemmer$out_grouping$LBaseStemmer$AIII(this, RussianStemmer.g_v, 1072, 1103)) { + break lab8; + } + break golab7; + } + if (this.cursor >= this.limit) { + break lab0; + } + ($__jsx_postinc_t = this.cursor, this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + this.I_p2 = this.cursor; + } + this.cursor = v_1; + return true; +}; + +RussianStemmer.prototype.r_mark_regions = RussianStemmer.prototype.r_mark_regions$; + +function RussianStemmer$r_mark_regions$LRussianStemmer$($this) { + var v_1; + var lab0; + var lab2; + var lab4; + var lab6; + var lab8; + var limit$0; + var $__jsx_postinc_t; + $this.I_pV = limit$0 = $this.limit; + $this.I_p2 = limit$0; + v_1 = $this.cursor; + lab0 = true; +lab0: + while (lab0 === true) { + lab0 = false; + golab1: + while (true) { + lab2 = true; + lab2: + while (lab2 === true) { + lab2 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, RussianStemmer.g_v, 1072, 1103)) { + break lab2; + } + break golab1; + } + if ($this.cursor >= $this.limit) { + break lab0; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + $this.I_pV = $this.cursor; + golab3: + while (true) { + lab4 = true; + lab4: + while (lab4 === true) { + lab4 = false; + if (! BaseStemmer$out_grouping$LBaseStemmer$AIII($this, RussianStemmer.g_v, 1072, 1103)) { + break lab4; + } + break golab3; + } + if ($this.cursor >= $this.limit) { + break lab0; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + golab5: + while (true) { + lab6 = true; + lab6: + while (lab6 === true) { + lab6 = false; + if (! BaseStemmer$in_grouping$LBaseStemmer$AIII($this, RussianStemmer.g_v, 1072, 1103)) { + break lab6; + } + break golab5; + } + if ($this.cursor >= $this.limit) { + break lab0; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + golab7: + while (true) { + lab8 = true; + lab8: + while (lab8 === true) { + lab8 = false; + if (! BaseStemmer$out_grouping$LBaseStemmer$AIII($this, RussianStemmer.g_v, 1072, 1103)) { + break lab8; + } + break golab7; + } + if ($this.cursor >= $this.limit) { + break lab0; + } + ($__jsx_postinc_t = $this.cursor, $this.cursor = ($__jsx_postinc_t + 1) | 0, $__jsx_postinc_t); + } + $this.I_p2 = $this.cursor; + } + $this.cursor = v_1; + return true; +}; + +RussianStemmer.r_mark_regions$LRussianStemmer$ = RussianStemmer$r_mark_regions$LRussianStemmer$; + +RussianStemmer.prototype.r_R2$ = function () { + return (! (this.I_p2 <= this.cursor) ? false : true); +}; + +RussianStemmer.prototype.r_R2 = RussianStemmer.prototype.r_R2$; + +function RussianStemmer$r_R2$LRussianStemmer$($this) { + return (! ($this.I_p2 <= $this.cursor) ? false : true); +}; + +RussianStemmer.r_R2$LRussianStemmer$ = RussianStemmer$r_R2$LRussianStemmer$; + +RussianStemmer.prototype.r_perfective_gerund$ = function () { + var among_var; + var v_1; + var lab0; + var lab1; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, RussianStemmer.a_0, 9); + if (among_var === 0) { + return false; + } + this.bra = this.cursor; + switch (among_var) { + case 0: + return false; + case 1: + lab0 = true; + lab0: + while (lab0 === true) { + lab0 = false; + v_1 = ((this.limit - this.cursor) | 0); + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "\u0430")) { + break lab1; + } + break lab0; + } + this.cursor = ((this.limit - v_1) | 0); + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "\u044F")) { + return false; + } + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + } + return true; +}; + +RussianStemmer.prototype.r_perfective_gerund = RussianStemmer.prototype.r_perfective_gerund$; + +function RussianStemmer$r_perfective_gerund$LRussianStemmer$($this) { + var among_var; + var v_1; + var lab0; + var lab1; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, RussianStemmer.a_0, 9); + if (among_var === 0) { + return false; + } + $this.bra = $this.cursor; + switch (among_var) { + case 0: + return false; + case 1: + lab0 = true; + lab0: + while (lab0 === true) { + lab0 = false; + v_1 = (($this.limit - $this.cursor) | 0); + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "\u0430")) { + break lab1; + } + break lab0; + } + $this.cursor = (($this.limit - v_1) | 0); + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "\u044F")) { + return false; + } + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + } + return true; +}; + +RussianStemmer.r_perfective_gerund$LRussianStemmer$ = RussianStemmer$r_perfective_gerund$LRussianStemmer$; + +RussianStemmer.prototype.r_adjective$ = function () { + var among_var; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, RussianStemmer.a_1, 26); + if (among_var === 0) { + return false; + } + this.bra = this.cursor; + switch (among_var) { + case 0: + return false; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + } + return true; +}; + +RussianStemmer.prototype.r_adjective = RussianStemmer.prototype.r_adjective$; + +function RussianStemmer$r_adjective$LRussianStemmer$($this) { + var among_var; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, RussianStemmer.a_1, 26); + if (among_var === 0) { + return false; + } + $this.bra = $this.cursor; + switch (among_var) { + case 0: + return false; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + } + return true; +}; + +RussianStemmer.r_adjective$LRussianStemmer$ = RussianStemmer$r_adjective$LRussianStemmer$; + +RussianStemmer.prototype.r_adjectival$ = function () { + var among_var; + var v_1; + var v_2; + var lab0; + var lab1; + var lab2; + if (! RussianStemmer$r_adjective$LRussianStemmer$(this)) { + return false; + } + v_1 = ((this.limit - this.cursor) | 0); + lab0 = true; +lab0: + while (lab0 === true) { + lab0 = false; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, RussianStemmer.a_2, 8); + if (among_var === 0) { + this.cursor = ((this.limit - v_1) | 0); + break lab0; + } + this.bra = this.cursor; + switch (among_var) { + case 0: + this.cursor = ((this.limit - v_1) | 0); + break lab0; + case 1: + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + v_2 = ((this.limit - this.cursor) | 0); + lab2 = true; + lab2: + while (lab2 === true) { + lab2 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "\u0430")) { + break lab2; + } + break lab1; + } + this.cursor = ((this.limit - v_2) | 0); + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "\u044F")) { + this.cursor = ((this.limit - v_1) | 0); + break lab0; + } + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + } + } + return true; +}; + +RussianStemmer.prototype.r_adjectival = RussianStemmer.prototype.r_adjectival$; + +function RussianStemmer$r_adjectival$LRussianStemmer$($this) { + var among_var; + var v_1; + var v_2; + var lab0; + var lab1; + var lab2; + if (! RussianStemmer$r_adjective$LRussianStemmer$($this)) { + return false; + } + v_1 = (($this.limit - $this.cursor) | 0); + lab0 = true; +lab0: + while (lab0 === true) { + lab0 = false; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, RussianStemmer.a_2, 8); + if (among_var === 0) { + $this.cursor = (($this.limit - v_1) | 0); + break lab0; + } + $this.bra = $this.cursor; + switch (among_var) { + case 0: + $this.cursor = (($this.limit - v_1) | 0); + break lab0; + case 1: + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + v_2 = (($this.limit - $this.cursor) | 0); + lab2 = true; + lab2: + while (lab2 === true) { + lab2 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "\u0430")) { + break lab2; + } + break lab1; + } + $this.cursor = (($this.limit - v_2) | 0); + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "\u044F")) { + $this.cursor = (($this.limit - v_1) | 0); + break lab0; + } + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + } + } + return true; +}; + +RussianStemmer.r_adjectival$LRussianStemmer$ = RussianStemmer$r_adjectival$LRussianStemmer$; + +RussianStemmer.prototype.r_reflexive$ = function () { + var among_var; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, RussianStemmer.a_3, 2); + if (among_var === 0) { + return false; + } + this.bra = this.cursor; + switch (among_var) { + case 0: + return false; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + } + return true; +}; + +RussianStemmer.prototype.r_reflexive = RussianStemmer.prototype.r_reflexive$; + +function RussianStemmer$r_reflexive$LRussianStemmer$($this) { + var among_var; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, RussianStemmer.a_3, 2); + if (among_var === 0) { + return false; + } + $this.bra = $this.cursor; + switch (among_var) { + case 0: + return false; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + } + return true; +}; + +RussianStemmer.r_reflexive$LRussianStemmer$ = RussianStemmer$r_reflexive$LRussianStemmer$; + +RussianStemmer.prototype.r_verb$ = function () { + var among_var; + var v_1; + var lab0; + var lab1; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, RussianStemmer.a_4, 46); + if (among_var === 0) { + return false; + } + this.bra = this.cursor; + switch (among_var) { + case 0: + return false; + case 1: + lab0 = true; + lab0: + while (lab0 === true) { + lab0 = false; + v_1 = ((this.limit - this.cursor) | 0); + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "\u0430")) { + break lab1; + } + break lab0; + } + this.cursor = ((this.limit - v_1) | 0); + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "\u044F")) { + return false; + } + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + } + return true; +}; + +RussianStemmer.prototype.r_verb = RussianStemmer.prototype.r_verb$; + +function RussianStemmer$r_verb$LRussianStemmer$($this) { + var among_var; + var v_1; + var lab0; + var lab1; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, RussianStemmer.a_4, 46); + if (among_var === 0) { + return false; + } + $this.bra = $this.cursor; + switch (among_var) { + case 0: + return false; + case 1: + lab0 = true; + lab0: + while (lab0 === true) { + lab0 = false; + v_1 = (($this.limit - $this.cursor) | 0); + lab1 = true; + lab1: + while (lab1 === true) { + lab1 = false; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "\u0430")) { + break lab1; + } + break lab0; + } + $this.cursor = (($this.limit - v_1) | 0); + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "\u044F")) { + return false; + } + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + } + return true; +}; + +RussianStemmer.r_verb$LRussianStemmer$ = RussianStemmer$r_verb$LRussianStemmer$; + +RussianStemmer.prototype.r_noun$ = function () { + var among_var; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, RussianStemmer.a_5, 36); + if (among_var === 0) { + return false; + } + this.bra = this.cursor; + switch (among_var) { + case 0: + return false; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + } + return true; +}; + +RussianStemmer.prototype.r_noun = RussianStemmer.prototype.r_noun$; + +function RussianStemmer$r_noun$LRussianStemmer$($this) { + var among_var; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, RussianStemmer.a_5, 36); + if (among_var === 0) { + return false; + } + $this.bra = $this.cursor; + switch (among_var) { + case 0: + return false; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + } + return true; +}; + +RussianStemmer.r_noun$LRussianStemmer$ = RussianStemmer$r_noun$LRussianStemmer$; + +RussianStemmer.prototype.r_derivational$ = function () { + var among_var; + var cursor$0; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, RussianStemmer.a_6, 2); + if (among_var === 0) { + return false; + } + this.bra = cursor$0 = this.cursor; + if (! (! (this.I_p2 <= cursor$0) ? false : true)) { + return false; + } + switch (among_var) { + case 0: + return false; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + } + return true; +}; + +RussianStemmer.prototype.r_derivational = RussianStemmer.prototype.r_derivational$; + +function RussianStemmer$r_derivational$LRussianStemmer$($this) { + var among_var; + var cursor$0; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, RussianStemmer.a_6, 2); + if (among_var === 0) { + return false; + } + $this.bra = cursor$0 = $this.cursor; + if (! (! ($this.I_p2 <= cursor$0) ? false : true)) { + return false; + } + switch (among_var) { + case 0: + return false; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + } + return true; +}; + +RussianStemmer.r_derivational$LRussianStemmer$ = RussianStemmer$r_derivational$LRussianStemmer$; + +RussianStemmer.prototype.r_tidy_up$ = function () { + var among_var; + this.ket = this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I(this, RussianStemmer.a_7, 4); + if (among_var === 0) { + return false; + } + this.bra = this.cursor; + switch (among_var) { + case 0: + return false; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + this.ket = this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "\u043D")) { + return false; + } + this.bra = this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "\u043D")) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "\u043D")) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + case 3: + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + break; + } + return true; +}; + +RussianStemmer.prototype.r_tidy_up = RussianStemmer.prototype.r_tidy_up$; + +function RussianStemmer$r_tidy_up$LRussianStemmer$($this) { + var among_var; + $this.ket = $this.cursor; + among_var = BaseStemmer$find_among_b$LBaseStemmer$ALAmong$I($this, RussianStemmer.a_7, 4); + if (among_var === 0) { + return false; + } + $this.bra = $this.cursor; + switch (among_var) { + case 0: + return false; + case 1: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + $this.ket = $this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "\u043D")) { + return false; + } + $this.bra = $this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "\u043D")) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 2: + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS($this, 1, "\u043D")) { + return false; + } + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + case 3: + if (! BaseStemmer$slice_from$LBaseStemmer$S($this, "")) { + return false; + } + break; + } + return true; +}; + +RussianStemmer.r_tidy_up$LRussianStemmer$ = RussianStemmer$r_tidy_up$LRussianStemmer$; + +RussianStemmer.prototype.stem$ = function () { + var v_1; + var v_2; + var v_3; + var v_4; + var v_5; + var v_6; + var v_7; + var v_8; + var v_9; + var lab0; + var lab1; + var lab2; + var lab3; + var lab4; + var lab5; + var lab6; + var lab7; + var lab8; + var lab9; + var lab10; + var cursor$0; + var limit$0; + var cursor$1; + var limit$1; + var cursor$2; + var cursor$3; + var limit$2; + var cursor$4; + var limit$3; + var cursor$5; + var limit_backward$0; + v_1 = this.cursor; + lab0 = true; +lab0: + while (lab0 === true) { + lab0 = false; + if (! RussianStemmer$r_mark_regions$LRussianStemmer$(this)) { + break lab0; + } + } + cursor$0 = this.cursor = v_1; + this.limit_backward = cursor$0; + cursor$1 = this.cursor = limit$0 = this.limit; + v_2 = ((limit$0 - cursor$1) | 0); + if (cursor$1 < this.I_pV) { + return false; + } + cursor$3 = this.cursor = this.I_pV; + v_3 = this.limit_backward; + this.limit_backward = cursor$3; + cursor$4 = this.cursor = (((limit$2 = this.limit) - v_2) | 0); + v_4 = ((limit$2 - cursor$4) | 0); + lab1 = true; +lab1: + while (lab1 === true) { + lab1 = false; + lab2 = true; + lab2: + while (lab2 === true) { + lab2 = false; + v_5 = ((this.limit - this.cursor) | 0); + lab3 = true; + lab3: + while (lab3 === true) { + lab3 = false; + if (! RussianStemmer$r_perfective_gerund$LRussianStemmer$(this)) { + break lab3; + } + break lab2; + } + cursor$2 = this.cursor = (((limit$1 = this.limit) - v_5) | 0); + v_6 = ((limit$1 - cursor$2) | 0); + lab4 = true; + lab4: + while (lab4 === true) { + lab4 = false; + if (! RussianStemmer$r_reflexive$LRussianStemmer$(this)) { + this.cursor = ((this.limit - v_6) | 0); + break lab4; + } + } + lab5 = true; + lab5: + while (lab5 === true) { + lab5 = false; + v_7 = ((this.limit - this.cursor) | 0); + lab6 = true; + lab6: + while (lab6 === true) { + lab6 = false; + if (! RussianStemmer$r_adjectival$LRussianStemmer$(this)) { + break lab6; + } + break lab5; + } + this.cursor = ((this.limit - v_7) | 0); + lab7 = true; + lab7: + while (lab7 === true) { + lab7 = false; + if (! RussianStemmer$r_verb$LRussianStemmer$(this)) { + break lab7; + } + break lab5; + } + this.cursor = ((this.limit - v_7) | 0); + if (! RussianStemmer$r_noun$LRussianStemmer$(this)) { + break lab1; + } + } + } + } + cursor$5 = this.cursor = (((limit$3 = this.limit) - v_4) | 0); + v_8 = ((limit$3 - cursor$5) | 0); + lab8 = true; +lab8: + while (lab8 === true) { + lab8 = false; + this.ket = this.cursor; + if (! BaseStemmer$eq_s_b$LBaseStemmer$IS(this, 1, "\u0438")) { + this.cursor = ((this.limit - v_8) | 0); + break lab8; + } + this.bra = this.cursor; + if (! BaseStemmer$slice_from$LBaseStemmer$S(this, "")) { + return false; + } + } + v_9 = ((this.limit - this.cursor) | 0); + lab9 = true; +lab9: + while (lab9 === true) { + lab9 = false; + if (! RussianStemmer$r_derivational$LRussianStemmer$(this)) { + break lab9; + } + } + this.cursor = ((this.limit - v_9) | 0); + lab10 = true; +lab10: + while (lab10 === true) { + lab10 = false; + if (! RussianStemmer$r_tidy_up$LRussianStemmer$(this)) { + break lab10; + } + } + limit_backward$0 = this.limit_backward = v_3; + this.cursor = limit_backward$0; + return true; +}; + +RussianStemmer.prototype.stem = RussianStemmer.prototype.stem$; + +RussianStemmer.prototype.equals$X = function (o) { + return o instanceof RussianStemmer; +}; + +RussianStemmer.prototype.equals = RussianStemmer.prototype.equals$X; + +function RussianStemmer$equals$LRussianStemmer$X($this, o) { + return o instanceof RussianStemmer; +}; + +RussianStemmer.equals$LRussianStemmer$X = RussianStemmer$equals$LRussianStemmer$X; + +RussianStemmer.prototype.hashCode$ = function () { + var classname; + var hash; + var i; + var char; + classname = "RussianStemmer"; + hash = 0; + for (i = 0; i < classname.length; i++) { + char = classname.charCodeAt(i); + hash = (hash << 5) - hash + char; + hash = hash & hash; + } + return (hash | 0); +}; + +RussianStemmer.prototype.hashCode = RussianStemmer.prototype.hashCode$; + +function RussianStemmer$hashCode$LRussianStemmer$($this) { + var classname; + var hash; + var i; + var char; + classname = "RussianStemmer"; + hash = 0; + for (i = 0; i < classname.length; i++) { + char = classname.charCodeAt(i); + hash = (hash << 5) - hash + char; + hash = hash & hash; + } + return (hash | 0); +}; + +RussianStemmer.hashCode$LRussianStemmer$ = RussianStemmer$hashCode$LRussianStemmer$; + +RussianStemmer.serialVersionUID = 1; +$__jsx_lazy_init(RussianStemmer, "methodObject", function () { + return new RussianStemmer(); +}); +$__jsx_lazy_init(RussianStemmer, "a_0", function () { + return [ new Among("\u0432", -1, 1), new Among("\u0438\u0432", 0, 2), new Among("\u044B\u0432", 0, 2), new Among("\u0432\u0448\u0438", -1, 1), new Among("\u0438\u0432\u0448\u0438", 3, 2), new Among("\u044B\u0432\u0448\u0438", 3, 2), new Among("\u0432\u0448\u0438\u0441\u044C", -1, 1), new Among("\u0438\u0432\u0448\u0438\u0441\u044C", 6, 2), new Among("\u044B\u0432\u0448\u0438\u0441\u044C", 6, 2) ]; +}); +$__jsx_lazy_init(RussianStemmer, "a_1", function () { + return [ new Among("\u0435\u0435", -1, 1), new Among("\u0438\u0435", -1, 1), new Among("\u043E\u0435", -1, 1), new Among("\u044B\u0435", -1, 1), new Among("\u0438\u043C\u0438", -1, 1), new Among("\u044B\u043C\u0438", -1, 1), new Among("\u0435\u0439", -1, 1), new Among("\u0438\u0439", -1, 1), new Among("\u043E\u0439", -1, 1), new Among("\u044B\u0439", -1, 1), new Among("\u0435\u043C", -1, 1), new Among("\u0438\u043C", -1, 1), new Among("\u043E\u043C", -1, 1), new Among("\u044B\u043C", -1, 1), new Among("\u0435\u0433\u043E", -1, 1), new Among("\u043E\u0433\u043E", -1, 1), new Among("\u0435\u043C\u0443", -1, 1), new Among("\u043E\u043C\u0443", -1, 1), new Among("\u0438\u0445", -1, 1), new Among("\u044B\u0445", -1, 1), new Among("\u0435\u044E", -1, 1), new Among("\u043E\u044E", -1, 1), new Among("\u0443\u044E", -1, 1), new Among("\u044E\u044E", -1, 1), new Among("\u0430\u044F", -1, 1), new Among("\u044F\u044F", -1, 1) ]; +}); +$__jsx_lazy_init(RussianStemmer, "a_2", function () { + return [ new Among("\u0435\u043C", -1, 1), new Among("\u043D\u043D", -1, 1), new Among("\u0432\u0448", -1, 1), new Among("\u0438\u0432\u0448", 2, 2), new Among("\u044B\u0432\u0448", 2, 2), new Among("\u0449", -1, 1), new Among("\u044E\u0449", 5, 1), new Among("\u0443\u044E\u0449", 6, 2) ]; +}); +$__jsx_lazy_init(RussianStemmer, "a_3", function () { + return [ new Among("\u0441\u044C", -1, 1), new Among("\u0441\u044F", -1, 1) ]; +}); +$__jsx_lazy_init(RussianStemmer, "a_4", function () { + return [ new Among("\u043B\u0430", -1, 1), new Among("\u0438\u043B\u0430", 0, 2), new Among("\u044B\u043B\u0430", 0, 2), new Among("\u043D\u0430", -1, 1), new Among("\u0435\u043D\u0430", 3, 2), new Among("\u0435\u0442\u0435", -1, 1), new Among("\u0438\u0442\u0435", -1, 2), new Among("\u0439\u0442\u0435", -1, 1), new Among("\u0435\u0439\u0442\u0435", 7, 2), new Among("\u0443\u0439\u0442\u0435", 7, 2), new Among("\u043B\u0438", -1, 1), new Among("\u0438\u043B\u0438", 10, 2), new Among("\u044B\u043B\u0438", 10, 2), new Among("\u0439", -1, 1), new Among("\u0435\u0439", 13, 2), new Among("\u0443\u0439", 13, 2), new Among("\u043B", -1, 1), new Among("\u0438\u043B", 16, 2), new Among("\u044B\u043B", 16, 2), new Among("\u0435\u043C", -1, 1), new Among("\u0438\u043C", -1, 2), new Among("\u044B\u043C", -1, 2), new Among("\u043D", -1, 1), new Among("\u0435\u043D", 22, 2), new Among("\u043B\u043E", -1, 1), new Among("\u0438\u043B\u043E", 24, 2), new Among("\u044B\u043B\u043E", 24, 2), new Among("\u043D\u043E", -1, 1), new Among("\u0435\u043D\u043E", 27, 2), new Among("\u043D\u043D\u043E", 27, 1), new Among("\u0435\u0442", -1, 1), new Among("\u0443\u0435\u0442", 30, 2), new Among("\u0438\u0442", -1, 2), new Among("\u044B\u0442", -1, 2), new Among("\u044E\u0442", -1, 1), new Among("\u0443\u044E\u0442", 34, 2), new Among("\u044F\u0442", -1, 2), new Among("\u043D\u044B", -1, 1), new Among("\u0435\u043D\u044B", 37, 2), new Among("\u0442\u044C", -1, 1), new Among("\u0438\u0442\u044C", 39, 2), new Among("\u044B\u0442\u044C", 39, 2), new Among("\u0435\u0448\u044C", -1, 1), new Among("\u0438\u0448\u044C", -1, 2), new Among("\u044E", -1, 2), new Among("\u0443\u044E", 44, 2) ]; +}); +$__jsx_lazy_init(RussianStemmer, "a_5", function () { + return [ new Among("\u0430", -1, 1), new Among("\u0435\u0432", -1, 1), new Among("\u043E\u0432", -1, 1), new Among("\u0435", -1, 1), new Among("\u0438\u0435", 3, 1), new Among("\u044C\u0435", 3, 1), new Among("\u0438", -1, 1), new Among("\u0435\u0438", 6, 1), new Among("\u0438\u0438", 6, 1), new Among("\u0430\u043C\u0438", 6, 1), new Among("\u044F\u043C\u0438", 6, 1), new Among("\u0438\u044F\u043C\u0438", 10, 1), new Among("\u0439", -1, 1), new Among("\u0435\u0439", 12, 1), new Among("\u0438\u0435\u0439", 13, 1), new Among("\u0438\u0439", 12, 1), new Among("\u043E\u0439", 12, 1), new Among("\u0430\u043C", -1, 1), new Among("\u0435\u043C", -1, 1), new Among("\u0438\u0435\u043C", 18, 1), new Among("\u043E\u043C", -1, 1), new Among("\u044F\u043C", -1, 1), new Among("\u0438\u044F\u043C", 21, 1), new Among("\u043E", -1, 1), new Among("\u0443", -1, 1), new Among("\u0430\u0445", -1, 1), new Among("\u044F\u0445", -1, 1), new Among("\u0438\u044F\u0445", 26, 1), new Among("\u044B", -1, 1), new Among("\u044C", -1, 1), new Among("\u044E", -1, 1), new Among("\u0438\u044E", 30, 1), new Among("\u044C\u044E", 30, 1), new Among("\u044F", -1, 1), new Among("\u0438\u044F", 33, 1), new Among("\u044C\u044F", 33, 1) ]; +}); +$__jsx_lazy_init(RussianStemmer, "a_6", function () { + return [ new Among("\u043E\u0441\u0442", -1, 1), new Among("\u043E\u0441\u0442\u044C", -1, 1) ]; +}); +$__jsx_lazy_init(RussianStemmer, "a_7", function () { + return [ new Among("\u0435\u0439\u0448\u0435", -1, 1), new Among("\u043D", -1, 2), new Among("\u0435\u0439\u0448", -1, 1), new Among("\u044C", -1, 3) ]; +}); +RussianStemmer.g_v = [ 33, 65, 8, 232 ]; + +var $__jsx_classMap = { + "src/among.jsx": { + Among: Among, + Among$SII: Among, + Among$SIIF$LBaseStemmer$B$LBaseStemmer$: Among$0 + }, + "src/stemmer.jsx": { + Stemmer: Stemmer, + Stemmer$: Stemmer + }, + "src/base-stemmer.jsx": { + BaseStemmer: BaseStemmer, + BaseStemmer$: BaseStemmer + }, + "src/russian-stemmer.jsx": { + RussianStemmer: RussianStemmer, + RussianStemmer$: RussianStemmer + } +}; + + +})(JSX); + +var Among = JSX.require("src/among.jsx").Among; +var Among$SII = JSX.require("src/among.jsx").Among$SII; +var Stemmer = JSX.require("src/stemmer.jsx").Stemmer; +var BaseStemmer = JSX.require("src/base-stemmer.jsx").BaseStemmer; +var RussianStemmer = JSX.require("src/russian-stemmer.jsx").RussianStemmer; diff --git a/help/ru/_static/ajax-loader.gif b/help/ru/_static/ajax-loader.gif new file mode 100644 index 00000000..61faf8ca Binary files /dev/null and b/help/ru/_static/ajax-loader.gif differ diff --git a/help/ru/_static/alert_info_32.png b/help/ru/_static/alert_info_32.png new file mode 100644 index 00000000..ea4d1baf Binary files /dev/null and b/help/ru/_static/alert_info_32.png differ diff --git a/help/ru/_static/alert_warning_32.png b/help/ru/_static/alert_warning_32.png new file mode 100644 index 00000000..a687c3dc Binary files /dev/null and b/help/ru/_static/alert_warning_32.png differ diff --git a/help/ru/_static/basic.css b/help/ru/_static/basic.css new file mode 100644 index 00000000..c7adab45 --- /dev/null +++ b/help/ru/_static/basic.css @@ -0,0 +1,665 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 59em; + max-width: 70em; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/help/ru/_static/bg-page.png b/help/ru/_static/bg-page.png new file mode 100644 index 00000000..fe0a6dc8 Binary files /dev/null and b/help/ru/_static/bg-page.png differ diff --git a/help/ru/_static/bullet_orange.png b/help/ru/_static/bullet_orange.png new file mode 100644 index 00000000..1cb8097c Binary files /dev/null and b/help/ru/_static/bullet_orange.png differ diff --git a/help/ru/_static/comment-bright.png b/help/ru/_static/comment-bright.png new file mode 100644 index 00000000..15e27edb Binary files /dev/null and b/help/ru/_static/comment-bright.png differ diff --git a/help/ru/_static/comment-close.png b/help/ru/_static/comment-close.png new file mode 100644 index 00000000..4d91bcf5 Binary files /dev/null and b/help/ru/_static/comment-close.png differ diff --git a/help/ru/_static/comment.png b/help/ru/_static/comment.png new file mode 100644 index 00000000..dfbc0cbd Binary files /dev/null and b/help/ru/_static/comment.png differ diff --git a/help/ru/_static/doctools.js b/help/ru/_static/doctools.js new file mode 100644 index 00000000..0c15c009 --- /dev/null +++ b/help/ru/_static/doctools.js @@ -0,0 +1,311 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var bbox = span.getBBox(); + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + var parentOfText = node.parentNode.parentNode; + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); \ No newline at end of file diff --git a/help/ru/_static/documentation_options.js b/help/ru/_static/documentation_options.js new file mode 100644 index 00000000..9de2c3fb --- /dev/null +++ b/help/ru/_static/documentation_options.js @@ -0,0 +1,9 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: '', + VERSION: '4.0.3', + LANGUAGE: 'ru', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' +}; \ No newline at end of file diff --git a/help/ru/_static/down-pressed.png b/help/ru/_static/down-pressed.png new file mode 100644 index 00000000..5756c8ca Binary files /dev/null and b/help/ru/_static/down-pressed.png differ diff --git a/help/ru/_static/down.png b/help/ru/_static/down.png new file mode 100644 index 00000000..1b3bdad2 Binary files /dev/null and b/help/ru/_static/down.png differ diff --git a/help/ru/_static/file.png b/help/ru/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/help/ru/_static/file.png differ diff --git a/help/ru/_static/haiku.css b/help/ru/_static/haiku.css new file mode 100644 index 00000000..75af2a5c --- /dev/null +++ b/help/ru/_static/haiku.css @@ -0,0 +1,376 @@ +/* + * haiku.css_t + * ~~~~~~~~~~~ + * + * Sphinx stylesheet -- haiku theme. + * + * Adapted from http://haiku-os.org/docs/Haiku-doc.css. + * Original copyright message: + * + * Copyright 2008-2009, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Francois Revol + * Stephan Assmus + * Braden Ewing + * Humdinger + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +html { + margin: 0px; + padding: 0px; + background: #FFF url(bg-page.png) top left repeat-x; +} + +body { + line-height: 1.5; + margin: auto; + padding: 0px; + font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; + min-width: 59em; + max-width: 70em; + color: #333333; +} + +div.footer { + padding: 8px; + font-size: 11px; + text-align: center; + letter-spacing: 0.5px; +} + +/* link colors and text decoration */ + +a:link { + font-weight: bold; + text-decoration: none; + color: #dc3c01; +} + +a:visited { + font-weight: bold; + text-decoration: none; + color: #892601; +} + +a:hover, a:active { + text-decoration: underline; + color: #ff4500; +} + +/* Some headers act as anchors, don't give them a hover effect */ + +h1 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h2 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h3 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h4 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +a.headerlink { + color: #a7ce38; + padding-left: 5px; +} + +a.headerlink:hover { + color: #a7ce38; +} + +/* basic text elements */ + +div.content { + margin-top: 20px; + margin-left: 40px; + margin-right: 40px; + margin-bottom: 50px; + font-size: 0.9em; +} + +/* heading and navigation */ + +div.header { + position: relative; + left: 0px; + top: 0px; + height: 85px; + /* background: #eeeeee; */ + padding: 0 40px; +} +div.header h1 { + font-size: 1.6em; + font-weight: normal; + letter-spacing: 1px; + color: #0c3762; + border: 0; + margin: 0; + padding-top: 15px; +} +div.header h1 a { + font-weight: normal; + color: #0c3762; +} +div.header h2 { + font-size: 1.3em; + font-weight: normal; + letter-spacing: 1px; + text-transform: uppercase; + color: #aaa; + border: 0; + margin-top: -3px; + padding: 0; +} + +div.header img.rightlogo { + float: right; +} + + +div.title { + font-size: 1.3em; + font-weight: bold; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-bottom: 25px; +} +div.topnav { + /* background: #e0e0e0; */ +} +div.topnav p { + margin-top: 0; + margin-left: 40px; + margin-right: 40px; + margin-bottom: 0px; + text-align: right; + font-size: 0.8em; +} +div.bottomnav { + background: #eeeeee; +} +div.bottomnav p { + margin-right: 40px; + text-align: right; + font-size: 0.8em; +} + +a.uplink { + font-weight: normal; +} + + +/* contents box */ + +table.index { + margin: 0px 0px 30px 30px; + padding: 1px; + border-width: 1px; + border-style: dotted; + border-color: #e0e0e0; +} +table.index tr.heading { + background-color: #e0e0e0; + text-align: center; + font-weight: bold; + font-size: 1.1em; +} +table.index tr.index { + background-color: #eeeeee; +} +table.index td { + padding: 5px 20px; +} + +table.index a:link, table.index a:visited { + font-weight: normal; + text-decoration: none; + color: #dc3c01; +} +table.index a:hover, table.index a:active { + text-decoration: underline; + color: #ff4500; +} + + +/* Haiku User Guide styles and layout */ + +/* Rounded corner boxes */ +/* Common declarations */ +div.admonition { + -webkit-border-radius: 10px; + -khtml-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; + border-style: dotted; + border-width: thin; + border-color: #dcdcdc; + padding: 10px 15px 10px 15px; + margin-bottom: 15px; + margin-top: 15px; +} +div.note { + padding: 10px 15px 10px 80px; + background: #e4ffde url(alert_info_32.png) 15px 15px no-repeat; + min-height: 42px; +} +div.warning { + padding: 10px 15px 10px 80px; + background: #fffbc6 url(alert_warning_32.png) 15px 15px no-repeat; + min-height: 42px; +} +div.seealso { + background: #e4ffde; +} + +/* More layout and styles */ +h1 { + font-size: 1.3em; + font-weight: bold; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-top: 30px; +} + +h2 { + font-size: 1.2em; + font-weight: normal; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-top: 30px; +} + +h3 { + font-size: 1.1em; + font-weight: normal; + color: #0c3762; + margin-top: 30px; +} + +h4 { + font-size: 1.0em; + font-weight: normal; + color: #0c3762; + margin-top: 30px; +} + +p { + text-align: justify; +} + +p.last { + margin-bottom: 0; +} + +ol { + padding-left: 20px; +} + +ul { + padding-left: 5px; + margin-top: 3px; +} + +li { + line-height: 1.3; +} + +div.content ul > li { + -moz-background-clip:border; + -moz-background-inline-policy:continuous; + -moz-background-origin:padding; + background: transparent url(bullet_orange.png) no-repeat scroll left 0.45em; + list-style-image: none; + list-style-type: none; + padding: 0 0 0 1.666em; + margin-bottom: 3px; +} + +td { + vertical-align: top; +} + +code { + background-color: #e2e2e2; + font-size: 1.0em; + font-family: monospace; +} + +pre { + border-color: #0c3762; + border-style: dotted; + border-width: thin; + margin: 0 0 12px 0; + padding: 0.8em; + background-color: #f0f0f0; +} + +hr { + border-top: 1px solid #ccc; + border-bottom: 0; + border-right: 0; + border-left: 0; + margin-bottom: 10px; + margin-top: 20px; +} + +/* printer only pretty stuff */ +@media print { + .noprint { + display: none; + } + /* for acronyms we want their definitions inlined at print time */ + acronym[title]:after { + font-size: small; + content: " (" attr(title) ")"; + font-style: italic; + } + /* and not have mozilla dotted underline */ + acronym { + border: none; + } + div.topnav, div.bottomnav, div.header, table.index { + display: none; + } + div.content { + margin: 0px; + padding: 0px; + } + html { + background: #FFF; + } +} + +.viewcode-back { + font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; + margin: -1px -10px; + padding: 0 12px; +} + +/* math display */ +div.math p { + text-align: center; +} \ No newline at end of file diff --git a/help/ru/_static/jquery-3.2.1.js b/help/ru/_static/jquery-3.2.1.js new file mode 100644 index 00000000..d2d8ca47 --- /dev/null +++ b/help/ru/_static/jquery-3.2.1.js @@ -0,0 +1,10253 @@ +/*! + * jQuery JavaScript Library v3.2.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2017-03-20T18:59Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.2.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Simple selector that can be filtered directly, removing non-Elements + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + // Complex selector, compare the two sets, removing non-Elements + qualifier = jQuery.filter( qualifier, elements ); + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( jQuery.isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ jQuery.camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( jQuery.camelCase ); + } else { + key = jQuery.camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( ">tbody", elem )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i, + val = 0; + + // If we already have the right measurement, avoid augmentation + if ( extra === ( isBorderBox ? "border" : "content" ) ) { + i = 4; + + // Otherwise initialize for horizontal or vertical properties + } else { + i = name === "width" ? 1 : 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with computed style + var valueIsBorderBox, + styles = getStyles( elem ), + val = curCSS( elem, name, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Fall back to offsetWidth/Height when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + if ( val === "auto" ) { + val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + } + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnothtmlwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, isFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + + +
+ + +
+

Changelog

+

About the word «crash»: When reading this changelog, you might be alarmed at the number of fixes +for «crashes». Be aware that when the word «crash» is used here, it refers to «soft crashes» which +don’t cause the application to quit. You simply get an error window that asks you if you want to +send the crash report to Hardcoded Software. Crashes that cause the application to quit are called +«hard crashes» in this changelog.

+
+

4.0.3 (2016-11-24)

+
    +
  • Add new picture cache backend: shelve
  • +
  • Make shelve picture cache backend the active one on MacOS to fix #394 more +elegantly. [cocoa]
  • +
  • Remove Sparkle (auto-updates) due to technical limitations. [cocoa]
  • +
+
+
+

4.0.2 (2016-10-09)

+
    +
  • Fix systematic crash in Picture Mode under MacOS Sierra. (#394)
  • +
  • No change for Linux. Just keeping version in sync.
  • +
+
+
+

4.0.1 (2016-08-24)

+
    +
  • Add Greek localization, by Gabriel Koutilellis. (#382)
  • +
  • Fix localization base path. [qt] (#378)
  • +
  • Fix broken load results dialog. [qt]
  • +
  • Fix crash on load results. [cocoa] (#380)
  • +
  • Save preferences more predictably. [qt] (#379)
  • +
  • Fix picture mode’s fuzzy block scanner threshold. (#387)
  • +
+
+
+

4.0.0 (2016-07-01)

+
    +
  • Merge Standard, Music and Picture editions in the same application!
  • +
  • Improve documentation. (#294)
  • +
  • Add Polish, Korean, Spanish and Dutch localizations.
  • +
  • qt: Fix wrong use_regexp option propagation to core. (#295)
  • +
  • qt: Fix progress window mistakenly showing up on startup. (#357)
  • +
  • Bump Python requirement to v3.4.
  • +
  • Bump OS X requirement to 10.8
  • +
  • Drop Windows support, maybe temporarily. +Details <https://www.hardcoded.net/archive2015`#2015-11-01>`_
  • +
  • cocoa: Drop iPhoto, Aperture and iTunes support. Was unmaintained and obsolete.
  • +
  • Drop «Audio Contents» scan type. Was confusing and seldom useful.
  • +
  • Change license to GPLv3
  • +
+
+
+

3.9.1 (2014-10-17)

+
    +
  • Fixed AttributeError: 'ComboboxModel' object has no attribute 'reset'. [Linux, Windows] (#254)
  • +
  • Fixed PermissionError on saving results. (#266)
  • +
  • Fixed a build problem introduced by Sphinx 1.2.3.
  • +
  • Updated German localisation, by Frank Weber.
  • +
+
+
+

3.9.0 (2014-04-19)

+
    +
  • This is mostly a dependencies upgrade.
  • +
  • Upgraded to Python 3.3.
  • +
  • Upgraded to Qt 5.
  • +
  • Minimum Windows version is now Windows 7 64bit.
  • +
  • Minimum Ubuntu version is now 14.04.
  • +
  • Minimum OS X version is now 10.7 (Lion).
  • +
  • … But with a couple of little improvements.
  • +
  • Improved documentation.
  • +
  • Overwrite subfolders“ state when setting states in folder dialog (#248)
  • +
  • The error report dialog now brings the user to Github issues.
  • +
+
+
+

3.8.0 (2013-12-07)

+
    +
  • Disable symlink/hardlink deletion option when not relevant. (#247)
  • +
  • Make Cmd+A select all folders in the Folder Selection dialog. [Mac] (#228)
  • +
  • Make non-numeric delta comparison case insensitive. (#239)
  • +
  • Fix surrogate-related UnicodeEncodeError on CSV export. (#210)
  • +
  • Fixed crash on Dupe Count sorting with Delta + Dupes Only. (#238)
  • +
  • Improved documentation.
  • +
  • Important internal refactorings.
  • +
  • Dropped Ubuntu 12.04 and 12.10 support.
  • +
  • Removed the fairware dialog (More Info).
  • +
+
+
+

3.7.1 (2013-08-19)

+
    +
  • Fixed folder scan type, which was broken in v3.7.0.
  • +
+
+
+

3.7.0 (2013-08-17)

+
    +
  • Improved delta values to support non-numerical values. (#213)
  • +
  • Improved the Re-Prioritize dialog’s UI. (#224)
  • +
  • Added hardlink/symlink support on Windows Vista+. (#220)
  • +
  • Dropped 32bit support on Mac OS X.
  • +
  • Added Vietnamese localization by Phan Anh.
  • +
+
+
+

3.6.1 (2013-04-28)

+
    +
  • Improved «Make Selection Reference» to make it clearer. (#222)
  • +
  • Improved «Open Selected» to allow opening more than one file at once. (#142)
  • +
  • Fixed a few typos here and there. (#216 #225)
  • +
  • Tweaked the fairware dialog (More Info).
  • +
  • Added Arch Linux packaging
  • +
  • Added a 64-bit build for Windows.
  • +
  • Improved Russian localization by Kyrill Detinov.
  • +
  • Improved Brazilian localization by Victor Figueiredo.
  • +
+
+
+

3.6.0 (2012-08-08)

+
    +
  • Added «Export to CSV». (#189)
  • +
  • Added «Replace with symlinks» to complement «Replace with hardlinks». [Mac, Linux] (#194)
  • +
  • dupeGuru now tells how many duplicates were affected after each re-prioritization operation. (#204)
  • +
  • Added Longest/Shortest filename criteria in the re-prioritize dialog. (#198)
  • +
  • Fixed result table cells which mistakenly became writable in v3.5.0. [Mac] (#203)
  • +
  • Fixed «Rename Selected» which was broken since v3.5.0. [Mac] (#202)
  • +
  • Fixed a bug where «Reset to Defaults» in the Columns menu wouldn’t refresh menu items“ marked state.
  • +
  • Added Brazilian localization by Victor Figueiredo.
  • +
+
+
+

3.5.0 (2012-06-01)

+
    +
  • Added a Deletion Options panel.
  • +
  • Greatly improved memory usage for big scans.
  • +
  • Added a keybinding for the filter field. (#182) [Mac]
  • +
  • Upgraded minimum requirements for Ubuntu to 12.04.
  • +
+
+
+

3.4.1 (2012-04-14)

+
    +
  • Fixed the «Folders» scan type. [Mac]
  • +
  • Fixed localization issues. [Windows, Linux]
  • +
+
+
+

3.4.0 (2012-03-29)

+
    +
  • Improved results window UI. [Windows, Linux]
  • +
  • Added a dialog to edit the Ignore List.
  • +
  • Added the ability to sort results by «marked» status.
  • +
  • Fixed «Open with default application». (#190)
  • +
  • Fixed a bug where there would be a false reporting of discarded matches. (#195)
  • +
  • Fixed various localization glitches.
  • +
  • Fixed hard crashes on crash reporting. (#196)
  • +
  • Fixed bug where the details panel would show up at inconvenient places in the screen. [Windows, Linux]
  • +
+
+
+

3.3.3 (2012-02-01)

+
    +
  • Fixed crash on adding some folders. [Mac OS X]
  • +
  • Added Ukrainian localization by Yuri Petrashko.
  • +
+
+
+

3.3.2 (2012-01-16)

+
    +
  • Fixed random hard crashes (yeah, again). [Mac OS X]
  • +
  • Fixed crash on Export to HTML. [Windows, Linux]
  • +
  • Added Armenian localization by Hrant Ohanyan.
  • +
  • Added Russian localization by Igor Pavlov.
  • +
+
+
+

3.3.1 (2011-12-02)

+
    +
  • Fixed a couple of nasty crashes.
  • +
+
+
+

3.3.0 (2011-11-30)

+
    +
  • Added multiple-selection in folder selection dialog for a more efficient folder removal. (#179)
  • +
  • Fixed a crash in the prioritize dialog. (#178)
  • +
  • Fixed a bug where mass marking with a filter would mark more than filtered duplicates. (#181)
  • +
  • Fixed random hard crashes. [Mac OS X] (#183 #184)
  • +
  • Added Czech localization by Aleš Nehyba.
  • +
  • Added Italian localization by Paolo Rossi.
  • +
+
+
+

3.2.1 (2011-10-02)

+
    +
  • Fixed a couple of broken action bindings from v3.2.0.
  • +
+
+
+

3.2.0 (2011-09-27)

+
    +
  • Added duplicate re-prioritization dialog. (#138)
  • +
  • Added font size preference for duplicate table. (#82)
  • +
  • Added Quicklook support. [Mac OS X] (#21)
  • +
  • Improved behavior of Mark Selected. (#139)
  • +
  • Improved filename sorting. (#169)
  • +
  • Added Chinese (Simplified) localization by Eric Dee.
  • +
  • Tweaked the fairware system.
  • +
  • Upgraded minimum requirements to OS X 10.6 and Ubuntu 11.04.
  • +
+
+
+

3.1.2 (2011-08-25)

+
    +
  • Fixed a bug preventing the Folders scan from working. (#172)
  • +
+
+
+

3.1.1 (2011-08-24)

+
    +
  • Added German localization by Gregor Tätzner.
  • +
  • Improved OS X Lion compatibility. [Mac OS X]
  • +
  • Made the file collection phase cancellable. (#168)
  • +
  • Fixed glitch in folder window upon selecting a folder state. [Windows, Linux] (#165)
  • +
  • Fixed a text coloring glitch in the results. (#156)
  • +
  • Fixed glitch in the sorting feature of the Folder column. (#161)
  • +
  • Make sure that saved results have the «.dupeguru» extension. [Linux] (#157)
  • +
+
+
+

3.1.0 (2011-04-16)

+
    +
  • Added the «Folders» scan type. (#89)
  • +
  • Fixed a couple of crashes. (#140 #149)
  • +
+
+
+

3.0.2 (2011-03-16)

+
    +
  • Fixed crash after removing marked dupes. (#140)
  • +
  • Fixed crash on error handling. [Windows] (#144)
  • +
  • Fixed crash on copy/move. [Windows] (#148)
  • +
  • Fixed crash when launching dupeGuru from a very long folder name. [Mac OS X] (#119)
  • +
  • Fixed a refresh bug in directory panel. (#153)
  • +
  • Improved reliability of the «Send to Trash» operation. [Linux]
  • +
  • Tweaked Fairware reminders.
  • +
+
+
+

3.0.1 (2011-01-27)

+
    +
  • Restored the context menu which had been broken in 3.0.0. [Mac OS X] (#133)
  • +
  • Fixed a bug where an «unsaved results» warning would be issued on quit even with empty results. (#134)
  • +
  • Removed focus from the cancel button in the progress dialog to avoid accidental cancellations. [Mac OS X] (#135)
  • +
  • Folders added through drag and drop are added to the recent folders list. (#136)
  • +
  • Added a debugging mode. (#132)
  • +
  • Fixed french localization glitches.
  • +
+
+
+

3.0.0 (2011-01-24)

+
    +
  • Re-designed the UI. (#129)
  • +
  • Internationalized dupeGuru and localized it to french. (#32)
  • +
  • Changed the format of the help file. (#130)
  • +
+
+
+

2.12.3 (2011-01-01)

+
    +
  • Fixed bug causing results to be corrupted after a scan cancellation. (#120)
  • +
  • Fixed crash when fetching Fairware unpaid hours. (#121)
  • +
  • Fixed crash when replacing files with hardlinks. (#122)
  • +
+
+
+

2.12.2 (2010-10-05)

+
    +
  • Fixed delta column colors which were broken since 2.12.0.
  • +
  • Fixed column sorting crash. (#108)
  • +
  • Fixed occasional crash during scan. (#106)
  • +
+
+
+

2.12.1 (2010-09-30)

+
    +
  • Re-licensed dupeGuru to BSD and made it Fairware.
  • +
+
+
+

2.12.0 (2010-09-26)

+
    +
  • Improved UI with a little revamp.
  • +
  • Added the possibility to place hardlinks to references after having deleted duplicates. [Mac OS X, Linux] (#91)
  • +
  • Added an option to ignore duplicates hardlinking to the same file. [Mac OS X, Linux] (#92)
  • +
  • Added multiple selection in the «Add Directory» dialog. [Mac OS X] (#105)
  • +
  • Fixed a bug preventing drag & drop from working in the Directories panel. [Windows, Linux]
  • +
+
+
+

2.11.1 (2010-08-26)

+
    +
  • Fixed HTML exporting which was broken in 2.11.0.
  • +
+
+
+

2.11.0 (2010-08-18)

+
    +
  • Added the ability to save results (and reload them) at arbitrary locations.
  • +
  • Improved the way reference files in dupe groups are chosen. (#15)
  • +
  • Remember size/position of all windows between launches. (#102)
  • +
  • Fixed a bug sometimes preventing dupeGuru from reloading previous results.
  • +
  • Fixed a bug sometimes causing the progress dialog to be stuck there. [Mac OS X] (#103)
  • +
  • Removed the Creation Date column, which wasn’t displaying the correct value anyway. (#101)
  • +
+
+
+

2.10.1 (2010-07-15)

+ +
+
+

2.10.0 (2010-04-13)

+
    +
  • Improved error messages when files can’t be sent to trash, moved or copied.
  • +
  • Added a custom command invocation action. (#12)
  • +
  • Filters are now applied on whole paths. (#4)
  • +
+
+
+

2.9.2 (2010-02-10)

+
    +
  • dupeGuru is now 64-bit on Mac OS X!
  • +
  • Fixed a crash upon quitting when support folder is not present. (#83)
  • +
  • Fixed a crash during sorting. (#85)
  • +
  • Fixed selection glitches, especially while renaming. (#93)
  • +
+
+
+

2.9.1 (2010-01-13)

+
    +
  • Improved memory usage for Contents scans. (#75)
  • +
  • Improved scanning speed when ref directories are involved. (#77)
  • +
  • Show a message dialog at the end of the scan if no duplicates are found. (#81)
  • +
  • Fixed a bug sometimes causing the small files threshold pref to be ignored. [Mac OS X] (#75)
  • +
+
+
+

2.9.0 (2009-11-03)

+
    +
  • Significantly improved speed and memory usage of big contents-based scans.
  • +
  • Added drag & drop support in the Directories panel. (#9)
  • +
  • Fixed a bug causing dupeGuru to be confused if a scanned file was moved during the scan. (#72)
  • +
  • Dropped support for Mac OS X 10.4 (Tiger)
  • +
+
+
+

2.8.2 (2009-10-14)

+
    +
  • Improved directory selection in the Directories panel (Windows). (#56)
  • +
  • Fixed a bug preventing dupeGuru from starting on certain machines (Windows). (#68)
  • +
  • Fixed a crash during very big scans. (#70)
  • +
+
+
+

2.8.1 (2009-10-02)

+
    +
  • Fixed crash with filtering when regular expressions were enabled. (#60)
  • +
  • Fixed crash when setting directories“ state. (Mac OS X) (#66)
  • +
  • Fixed crash with Make Reference when certain filters are applied. (Mac OS X) (#55)
  • +
  • Improved error handling during delete/move/copy actions. (#62 #65)
  • +
+
+
+

2.8.0 (2009-09-07)

+
    +
  • Added support for all kinds of bundle (not just applications) (Mac OS X) (#11)
  • +
  • Re-introduced the Export to XHTML feature to Windows. (#14)
  • +
  • Improved Export to XHTML speed. (#14)
  • +
  • Improved Contents scanning speed for large files. (#33)
  • +
  • Improved the grouping algorithm to reduce the number of discarded files in non-exact scans. (#51)
  • +
  • Stopped showing the same file on the 2 sides of the details panel when a ref file is selected. (#50)
  • +
  • Fixed crashes in the Directories panel. (#46)
  • +
+
+
+

2.7.3 (2009-06-20)

+
    +
  • +
    Fixed bugs with selection being jumpy during «Make Reference» actions and Power Marker
    +
    switches. (#3)
    +
    +
  • +
  • Fixed crash happening when a file with non-roman characters couldn’t be analyzed. (#30)
  • +
  • Fixed crash sometimes happening during the file collection phase in scanning. (#38)
  • +
  • Restored double-click and right-click behavior lost in the PyQt move (Windows). (#34 #35)
  • +
+
+
+

2.7.2 (2009-06-10)

+
    +
  • Fixed an occasional crash on Copy/Move operations. (#16)
  • +
  • Added automatic exclusion for sensible folders (like system folders). (#20)
  • +
  • Fixed an occasional crash when application files were part of the results (Mac OS X). (#25)
  • +
+
+
+

2.7.1 (2009-05-29)

+
    +
  • Fixed a bug causing crashes when having application files in the results.
  • +
  • Fixed a bug causing a GUI freeze at the beginning of a scan with a lot of files.
  • +
  • Fixed a bug that sometimes caused a crash when an action was cancelled, and then started again.
  • +
+
+
+

2.7.0 (2009-05-25)

+
    +
  • Converted the Windows GUI to Qt.
  • +
  • Improved the reliability of the scanning process.
  • +
+
+
+

2.6.1 (2009-03-27)

+
    +
  • Fixed an occasional crash caused by permission issues.
  • +
  • +
    Fixed a bug where the «X discarded» notice would show a too large number of discarded
    +
    duplicates.
    +
    +
  • +
+
+
+

2.6.0 (2008-09-10)

+
    +
  • Added a small file threshold preference.
  • +
  • Added a notice in the status bar when matches were discarded during the scan.
  • +
  • Improved duplicate prioritization (smartly chooses which file you will keep).
  • +
  • Improved scan progress feedback.
  • +
  • Improved responsiveness of the user interface for certain actions.
  • +
+
+
+

2.5.4 (2008-08-10)

+
    +
  • Improved the speed of results loading and saving.
  • +
  • Fixed a crash sometimes occurring during duplicate deletion.
  • +
+
+
+

2.5.3 (2008-07-08)

+
    +
  • Improved unicode handling for filenames. dupeGuru will now find a lot more duplicates if your files have non-ascii characters in it.
  • +
  • Fixed «Clear Ignore List» crash in Windows.
  • +
+
+
+

2.5.2 (2008-01-10)

+
    +
  • Improved the handling of low memory situations.
  • +
  • Improved the directory panel. The «Remove» button changes to «Put Back» when an excluded directory is selected.
  • +
  • Improved scan, delete and move speed in situations where there were a lot of duplicates.
  • +
  • Fixed occasional crashes when moving bundles (such as .app files).
  • +
  • Fixed occasional crashes when moving a lot of files at once.
  • +
+
+
+

2.5.1 (2007-11-22)

+
    +
  • Added the «Remove empty folders» option.
  • +
  • Fixed results load/save issues.
  • +
  • Fixed occasional status bar inaccuracies when the results are filtered.
  • +
+
+
+

2.5.0 (2007-09-15)

+
    +
  • Added post scan filtering.
  • +
  • Fixed issues with the rename feature under Windows
  • +
  • Fixed some user interface annoyances under Windows
  • +
+
+
+

2.4.8 (2007-04-14)

+
    +
  • Improved UI responsiveness (using threads) under Mac OS X.
  • +
  • Improved result load/save speed and memory usage.
  • +
+
+
+

2.4.7 (2007-03-10)

+
    +
  • Fixed a «bad file descriptor» error occasionally popping up.
  • +
  • Fixed a bug with non-latin directory names.
  • +
+
+
+

2.4.6 (2007-02-10)

+
    +
  • Added Re-orderable columns. In fact, I re-added the feature which was lost in the C# conversion in 2.4.0 (Windows).
  • +
  • Changed the behavior of the scanning engine when setting the hardness to 100. It will now only match files that have their words in the same order.
  • +
  • Fixed a bug with all the Delete/Move/Copy actions with certain kinds of files.
  • +
+
+
+

2.4.5 (2007-01-11)

+
    +
  • Fixed a bug with the Move action.
  • +
+
+
+

2.4.4 (2007-01-07)

+
    +
  • Fixed a «ghosting» bug. Dupes deleted by dupeGuru would sometimes come back in subsequent scans (Windows).
  • +
  • Fixed bugs sometimes making dupeGuru crash when marking a dupe (Windows).
  • +
  • Fixed some minor visual glitches (Windows).
  • +
+
+
+

2.4.3 (2006-12-08)

+
    +
  • Fixed a mishandling of «.app» files (OS X).
  • +
  • Fixed a bug preventing files from «reference» directories to be displayed in blue in the results (Windows).
  • +
  • Fixed a bug preventing some files to be sent to the recycle bin (Windows).
  • +
  • Fixed a bug in the packaging preventing certain Windows configurations to start dupeGuru at all.
  • +
+
+
+

2.4.2 (2006-11-18)

+
    +
  • Fixed a bug with directory states.
  • +
+
+
+

2.4.1 (2006-11-15)

+
    +
  • Fixed a bug causing the ignore list not to be saved.
  • +
  • Fixed a bug sometimes making delete and move operations stall.
  • +
+
+
+

2.4.0 (2006-11-10)

+
    +
  • Changed the Windows interface. It is now .NET based.
  • +
  • Added an auto-update feature to the windows version.
  • +
  • Changed the way power marking works. It is now a mode instead of a separate window.
  • +
  • Changed the «Size (MB)» column for a «Size (KB)» column. The values are now «ceiled» instead of rounded. Therefore, a size «0» is now really 0 bytes, not just a value too small to be rounded up. It is also the case for delta values.
  • +
  • Removed the min word length/count options. These came from Mp3 Filter, and just aren’t used anymore. Word weighting does pretty much the same job.
  • +
+
+
+

2.3.4 (2006-11-07)

+
    +
  • Improved speed and memory usage of the scanning engine, again. Does it mean there was a lot of improvements to be made? Nah…
  • +
+
+
+

2.3.3 (2006-11-02)

+
    +
  • Improved speed and memory usage of the scanning engine, especially when the scan results in a lot of duplicates.
  • +
  • Now I wonder if Sparkle is going to work well…
  • +
+
+
+

2.3.2 (2006-10-16)

+
    +
  • Added an auto-update feature in the Mac OS X version (with Sparkle).
  • +
  • Fixed a bug preventing some duplicate reports to be created correctly under Windows.
  • +
+
+
+

2.3.1 (2006-10-02)

+
    +
  • Fixed a bug preventing some duplicates to be found, especially when scanning lots of files.
  • +
+
+
+

2.3.0 (2006-09-22)

+
    +
  • Added XHTML export feature.
  • +
+
+
+

2.2.10 (2006-08-31)

+
    +
  • Added sticky columns.
  • +
  • Fixed an issue with file caching between scans.
  • +
  • Fixed an issue preventing some duplicates from being deleted/moved/copied.
  • +
+
+
+

2.2.9 (2006-08-27)

+
    +
  • Fixed an issue with ignore list and unicode.
  • +
  • Fixed an issue with file attribute fetching sometimes causing dupeGuru to crash.
  • +
  • Fixed an issue in the directories panel under Windows.
  • +
+
+
+

2.2.8 (2006-08-17)

+
    +
  • Fixed an issue in the duplicate seeking engine preventing some duplicates to be found.
  • +
+
+
+

2.2.7 (2006-08-12)

+
    +
  • Improved unicode support.
  • +
  • Improved the «Reveal in Finder» («Open Containing Folder» in Windows) feature so it selects the file in the folder it opens.
  • +
+
+
+

2.2.6 (2006-08-07)

+
    +
  • Improved the ignore list system.
  • +
  • dupeGuru is now a Universal application on Mac OS X.
  • +
+
+
+

2.2.5 (2006-07-26)

+
    +
  • Improved application (.app) dupe detection on Mac OS X.
  • +
  • Fixed an issue that occasionally made dupeGuru crash on startup.
  • +
+
+
+

2.2.4 (2006-06-27)

+
    +
  • Fixed an issue with Move and Copy features.
  • +
+
+
+

2.2.3 (2006-06-15)

+
    +
  • Improved duplicate scanning speed.
  • +
  • Added a warning that a file couldn’t be renamed if a file with the same name already exists.
  • +
+
+
+

2.2.2 (2006-06-07)

+
    +
  • Added «Rename Selected» feature.
  • +
  • Fixed some minor issues with «Reload Last Results» feature.
  • +
  • Fixed ignore list issues.
  • +
+
+
+

2.2.1 (2006-05-22)

+
    +
  • Fixed occasional progress bar woes under Windows.
  • +
  • Fixed a bug in the registration system under Windows.
  • +
  • Nothing has been changed in the Mac OS X version, but I want to keep version in sync.
  • +
+
+
+

2.2.0 (2006-05-10)

+
    +
  • Added destination path re-creation options.
  • +
  • Added an ignore list.
  • +
  • Changed the main icon.
  • +
  • Improved dramatically the delta values feature.
  • +
+
+
+

2.1.2 (2006-04-18)

+
    +
  • Added the «Match similar words» option.
  • +
  • Fixed Power marking issues under Mac.
  • +
+
+
+

2.1.1 (2006-04-14)

+
    +
  • Added the «Display delta values» option.
  • +
  • Improved Power marking sorting speed under Mac.
  • +
  • Fixed Power marking sorting issues.
  • +
+
+
+

2.1.0 (2006-04-03)

+
    +
  • Added the Power Marker feature.
  • +
  • Fixed a column sorting bug. The results would sometimes lose their sort order.
  • +
  • Fixed a bug with the Make Reference feature. The results sometimes wasn’t correctly refreshed after the reference switch.
  • +
+
+
+

2.0.1 (2006-03-23)

+
    +
  • Fixed an issue occasionally occurring when trying to reload results from removable media that is no longer present.
  • +
+
+
+

2.0.0 (2006-03-17)

+
    +
  • Complete rewrite.
  • +
  • Now runs on Mac OS X.
  • +
+
+
+

1.0.0 (2004-09-24)

+
    +
  • Initial release.
  • +
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/ru/faq.html b/help/ru/faq.html new file mode 100644 index 00000000..1302b1ea --- /dev/null +++ b/help/ru/faq.html @@ -0,0 +1,108 @@ + + + + + + + + Часто задаваемые вопросы — Документация dupeGuru 4.0.3 + + + + + + + + + + + + + + + + +
+ + +
+

Часто задаваемые вопросы

+
+

Что такое dupeGuru?

+
+
+

Что делает его лучше, чем другие сканеры дублировать?

+

Сканирования является чрезвычайно гибкой. Вы можете настроить его, чтобы действительно получить, каких результатов вы хотите. Вы можете прочитать больше о опция настройки dupeGuru в Настройки.

+
+
+

Насколько безопасно использовать dupeGuru?

+

Очень безопасной. dupeGuru был разработан, чтобы убедиться, что вы не удаляете файлы, которые вы не хотели удалить. Во-первых, существует система отсчета папку, которая позволяет определить папки, в которых вы абсолютно не хотите dupeGuru, чтобы вы удаляете файлы там, и тогда есть система контрольной группы, что гарантирует, что вы всегда держать по крайней мере один член группы дубликатов.

+
+
+

Каковы ограничения демо dupeGuru?

+

В демо-режиме, вы можете только выполнять действия над 10 дубликаты сразу. в +Fairware режиме, однако, Есть никаких ограничений.

+
+
+

Знак коробку файл я хочу удалить отключена. Что я должен сделать?

+

Вы не можете пометить ссылки (первый файл) дубликат группы. Однако то, что вы можете сделать, заключается в содействии дублировать файл справки. Таким образом, если файл, который Вы хотите, чтобы отметить это ссылки, выделите дубликатов файлов в группу, которую вы хотите продвигать на ссылку, и нажмите на кнопку Действия -> Добавить выбранной ссылки . Если ссылка файл из папки ссылки (имя файла написаны на синими буквами), вы не можете удалить его из исходного положения.

+
+
+

У меня есть папка, из которой я действительно не хочу, чтобы удалить файлы.

+

IЕсли вы хотите быть уверены, что dupeGuru никогда не будет удалять файл из определенной папки, убедитесь, что установили в состояние Ссылка на: документ: папки.

+
+
+

Что это за „(X отбрасывается) «уведомление в строке состояния?

+

В некоторых случаях, несколько матчей не включены в окончательные результаты по соображениям безопасности. Позвольте мне привести пример. У нас есть 3 файла: A, B и C. Мы сканируем их с помощью фильтра низких твердости.Сканер определяет, что матчи с B, матчи с С, но делает B ** не ** матч с С. При этом, dupeGuru имеет вид проблемы. Она не может создать дубликат группы А, В и С в это, потому что не все файлы в группе будет соответствовать вместе. Это может создать 2 группы: одна группа AB, а затем одна группа AC, но это не будет, по соображениям безопасности. Давайте думать об этом: если Б не совпадает с С, она, вероятно, означает, что либо B, C или оба на самом деле не дубликаты. Если не было бы 2 группы (АВ и АС), вы бы в конечном итоге удалить оба B и C. И если один из них не дублировать, что на самом деле не то, что вы хотите делать, правильно? Так что dupeGuru делает в таком случае является, чтобы отменить матч AC (и добавляет уведомление в строке состояния). Таким образом, если вы удалите B и повторно запустить сканирование, вам придется соответствовать переменного тока в следующий результат.

+
+
+

Я хочу, чтобы отметить все файлы из определенной папки. Что я могу сделать?

+

Включить: документ: обманутые Только <результаты> режим и нажать на папку колонки для сортировки дубликатов по папкам. Затем он будет легким для вас, чтобы выбрать все дубликаты из той же папке, а затем нажать клавишу пробел, чтобы отметить все выбранные дубликатов.

+
+
+

Я пытался отправить свои дубликаты в корзину, но dupeGuru говорит мне, он не может это сделать. Почему? Что я могу сделать?

+

Большую часть времени, поэтому dupeGuru не можете отправлять файлы в корзину из-за права доступа к файлам. Вы должны написать * * разрешения на файлы, которые вы хотите отправить в корзину. Если вы не знакомы с командной строкой, вы можете использовать утилиты, такие как BatChmod <http://macchampion.com/arbysoft/BatchMod> _ исправить Ваши права.

+
+
Если dupeGuru еще дает вам неприятности после фиксации ваших прав, было несколько случаев, когда с помощью «Перемещение Помечено к …» в качестве обходного пути сделали свое дело. Таким образом, вместо отправки файлов в корзину, вы посылаете их во временную папку с «Переместить Отмеченные к …» действия, а затем вы удалите эту временную папку вручную.
+

Если все это не так, контакт с поддержки HS, мы поможем Вас.

+
+
+

План

+

This FAQ qestion is outdated, see english version.

+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/ru/folders.html b/help/ru/folders.html new file mode 100644 index 00000000..035ce977 --- /dev/null +++ b/help/ru/folders.html @@ -0,0 +1,84 @@ + + + + + + + + Выбор папки — Документация dupeGuru 4.0.3 + + + + + + + + + + + + + + + + +
+ + +
+

Выбор папки

+

Первое окно, вы видите, когда вы запускаете dupeGuru это окно выбора папки. Это окно содержит список папок, которые будут сканироваться при нажатии на Scan.

+

Это окно довольно проста в использовании. Если вы хотите добавить папку, нажмите на кнопку +. Если вы добавили папки прежде, всплывающее меню со списком последних папки добавил появится. Вы можете нажать на одну из них, чтобы добавить его прямо в свой список. Если нажать на первый пункт всплывающего меню, Добавить новую папку …, вам будет предложено ввести папку добавить. Если вы никогда не добавляется папка, не появится меню, и вы будете непосредственно будет предложено ввести новую папку добавить.

+

Альтернативный способ для добавления папок в список, чтобы перетащить их в списке.

+

Чтобы удалить папку, выберите папку, удалить, и нажмите на -. Если папке выбирается при нажатии кнопки, выбранной папки будет установлен в ** ** исключены состояния (см. ниже), а не удален.

+
+

Папка государств

+

Каждая папка может находиться в одном из этих 3-х государств:

+
    +
  • Нормальный: дубликаты найдены в эту папку можно удалить.
  • +
  • Справка: Дубликаты найти в этой папке не может быть удалены . Файлы из этой папки можно только в конечном итоге в ссылка позиция в группе обмануть. Если более чем один файл из папки ссылку в конечном итоге в той же группе обмануть, только один, будут сохранены.Другие будут удалены из группы.
  • +
  • Не включено: Файлы в этом каталоге не будет включен в проверку.
  • +
+

Состояние по умолчанию к папке, конечно, Нормальный. Вы можете использовать Ссылка состояние для папки, если вы хотите быть уверены, что вы не будете удалять любые файлы из него.

+

Когда вы устанавливаете состояние каталог, все подпапки этой папки автоматически наследует это состояние, если явно не включенное состояние подпапку в.

+
+

План

+

Add iPhoto/Aperture/iTunes libraries notes

+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/ru/genindex.html b/help/ru/genindex.html new file mode 100644 index 00000000..acab415d --- /dev/null +++ b/help/ru/genindex.html @@ -0,0 +1,59 @@ + + + + + + + + + Алфавитный указатель — Документация dupeGuru 4.0.3 + + + + + + + + + + + + + + +
+ + + +

Алфавитный указатель

+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/ru/index.html b/help/ru/index.html new file mode 100644 index 00000000..da8ca3a8 --- /dev/null +++ b/help/ru/index.html @@ -0,0 +1,94 @@ + + + + + + + + dupeGuru help — Документация dupeGuru 4.0.3 + + + + + + + + + + + + + + + +
+ + +
+

dupeGuru help

+

Хотя dupeGuru может быть легко использована без документации, чтение этого файла поможет вам освоить его. Если вы ищете руководство для вашей первой дублировать сканирования, вы можете взглянуть на раздел Быстрый Начало.

+

Это хорошая идея, чтобы сохранить dupeGuru обновлен. Вы можете скачать последнюю версию на своей homepage. +Содержание:

+ +
+ + + +
+ + + + + \ No newline at end of file diff --git a/help/ru/objects.inv b/help/ru/objects.inv new file mode 100644 index 00000000..1154c7d5 Binary files /dev/null and b/help/ru/objects.inv differ diff --git a/help/ru/preferences.html b/help/ru/preferences.html new file mode 100644 index 00000000..eff7d6b7 --- /dev/null +++ b/help/ru/preferences.html @@ -0,0 +1,81 @@ + + + + + + + + Предпочтения — Документация dupeGuru 4.0.3 + + + + + + + + + + + + + + + + +
+ + +
+

Предпочтения

+

Можно смешивать файл вида: Если вы установите этот флажок, дублировать группам разрешается есть файлы с различными расширениями. Если вы не проверить его, ну, они не являются!

+

Игнорировать дубликаты hardlinking в тот же файл: Если эта опция включена, dupeGuru проверит дубликаты, чтобы увидеть если они ссылаются на тот же индексный дескриптор. Если они это сделают, они не будут считаться дубликатами. (Только для OS X и Linux)

+

Использование регулярных выражений при фильтрации: Если вы отметите этот флажок, фильтрация будет рассматривать ваш запрос фильтра, как регулярное выражение. Объясняя их выходит за рамки этого документа.Хорошее место для начала обучения он regular-expressions.info.

+

Удаление пустых папок после удаления или перемещения: Когда эта опция включена, папки будут удалены через файл удален или перемещен и папка пуста.

+

Копирование и перемещение: Определяет, как операции копирования и перемещения (в меню Действия) будет себя вести.

+
    +
  • Право на назначение: Все файлы будут отправлены непосредственно в пункт назначения, не пытаясь воссоздать исходный путь вообще.
  • +
  • Повторно относительный путь: путь исходный файл будет воссоздан в папке назначения, вплоть до корневого выделение в панели директорей. Например, если вы добавили /Users/foobar/SomeFolder на панель Каталоги и перемещении /Users/foobar/SomeFolder/SubFolder/SomeFile.ext до места назначения /Users/foobar/MyDestination, конечным пунктом назначения для файла будет /Users/foobar/MyDestination/SubFolder (SomeFolder были сокращены с пути источника в конечный пункт назначения.).
  • +
  • Повторно абсолютный путь: путь исходный файл будет воссоздан в папке назначения в полном комплекте. Например, если вы перемещаете /Users/foobar/SomeFolder/SubFolder/SomeFile.ext до места назначения /Users/foobar/MyDestination, конечным пунктом назначения для файла будет /Users/foobar/MyDestination/Users/foobar/SomeFolder/SubFolder.
  • +
+

Во всех случаях, dupeGuru красиво ручки конфликтов имен путем добавления номера назначения имя файла, если имя файла уже существует в месте назначения.

+

Специальной команды: Это предпочтение определяет команду, которая будет вызываться «Вызов специальной команды» действия. Вы можете ссылаться ни на какие внешние приложения через это действие. Это может быть полезно, если, например, у вас есть хорошее приложение сравниваете установлены.

+

Формат команды такой же, как то, что вы должны написать в командной строке, за исключением того, что Есть 2 заполнителей: %d and %r. Эти заполнители будут заменены на путь выбран обманут (%d) и путь к ссылке на файл выбранного обмануть (%r).

+

Если путь к исполняемому содержит пробелы, необходимо заключить его в «» кавычки. Вы также должны приложить заполнителей в кавычки, потому что это очень возможно, что путь к обманутых и ссылки будут содержать пробелы. Вот пример пользовательской команды:

+
+
«C:Program FilesSuperDiffProgSuperDiffProg.exe» «%d» «%r»
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/ru/quick_start.html b/help/ru/quick_start.html new file mode 100644 index 00000000..44deb97d --- /dev/null +++ b/help/ru/quick_start.html @@ -0,0 +1,76 @@ + + + + + + + + Быстрый старт — Документация dupeGuru 4.0.3 + + + + + + + + + + + + + + + + +
+ + +
+

Быстрый старт

+

Чтобы вы быстро начали с dupeGuru, давайте просто делать сканирование с помощью стандартных настроек по умолчанию.

+
    +
  • Запуск dupeGuru.
  • +
  • Добавление папок для сканирования либо перетащить & капли или кнопку «+».
  • +
  • Нажмите на сканирование.
  • +
  • Подождите, пока процесс сканирования завершен.
  • +
  • Посмотрите на каждый дубликат (файлы, которые отступом) и убедитесь, что это действительно дубликат ссылкой группы (файл выше дублировать без отступа и инвалидов окна знак).
  • +
  • Если файл ложных дубликатов, выделите ее и нажмите Действия -> Удалить выбранные из результатов.
  • +
  • Если вы уверены, что нет ложных дубликатов в результатах, нажмите на Изменить -> Отметить Все, а затем Действия -> Отправить Помечено в Корзину.
  • +
+

Это только основные сканирования. Есть много настройки вы можете сделать, чтобы получить разные результаты и несколько методов изучения и изменения ваших результатов. Чтобы узнать о них, только что прочитал остальную часть этого файла справки.

+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/ru/reprioritize.html b/help/ru/reprioritize.html new file mode 100644 index 00000000..935c8f7f --- /dev/null +++ b/help/ru/reprioritize.html @@ -0,0 +1,84 @@ + + + + + + + + Повторное приоритетов дубликатов — Документация dupeGuru 4.0.3 + + + + + + + + + + + + + + + + +
+ + +
+

Повторное приоритетов дубликатов

+

dupeGuru пытается автоматически определить, какие дубликат должен отправиться в ссылку каждой группы +позиции, но иногда это делается неправильно. Во многих случаях, умный обмануть сортировки с «Ценности Дельта» +и «обманутые Только» варианты в дополнение к «Сделать выбранной ссылки» действие делает трюк, но +иногда, более мощный вариант не требуется. Здесь изменения приоритетов в диалог вступает в +играть. Вы можете вызвать его через «изменить приоритеты Результаты» пункт в меню «Действия».

+

Этот диалог позволяет вам выбрать критерии, по которым ссылка обмануть будут отобраны в +каждой группе обмануть.Список доступных критериев слева и перечень критериев вы +Выбранная справа.

+

Критериев категории следуют аргумент. Например, «Размер (Высший)» означает, что обмануть +с крупным размером победит. «Свойства папки (/ Foo / Bar)» означает, что обманутые в этой папке будет победить. Для добавления +критерий правом списке, сначала выберите категорию в выпадающем списке, затем выберите +subargument в приведенном ниже списке, а затем нажмите на правую стрелку кнопки.

+

Порядок списка справа важно (вы можете изменить порядок элементов через перетащить и отпустить). когда +сбор обмануть для справки позицию, первый критерий используется. Если есть галстук, второй +критерий используется и так далее и так далее. Например, если ваши аргументы «Размер (высший)», а затем +«Имя файла (Не оканчивается на номер)», ссылке на файл, который будет выбран в группе будет +крупнейших файл, а если два или несколько файлов имеют одинаковый размер, который имеет имя файла с +не заканчивается номер будет использоваться. Когда все критерии привести к связи, порядок, в котором обманутые +ранее были в группе будет использоваться.

+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/ru/results.html b/help/ru/results.html new file mode 100644 index 00000000..b15999ea --- /dev/null +++ b/help/ru/results.html @@ -0,0 +1,153 @@ + + + + + + + + Результаты — Документация dupeGuru 4.0.3 + + + + + + + + + + + + + + + + +
+ + +
+

Результаты

+

Когда dupeGuru завершения сканирования на наличие дубликатов, он покажет его результаты в виде дубликата список группы.

+
+

О дубликат группы

+

Дубликат группа представляет собой группу файлов, которые весь матч вместе. Каждая группа имеет ссылке на файл и одного или более одинаковых файлов. Ссылки файл первый файл группы. Его марка окно отключено. Под ним, и с отступом, которые дубликатов файлов.

+

Вы можете отметить дубликатов файлов, но вы никогда не можете пометить ссылки файл группы. Это мера безопасности, чтобы предотвратить dupeGuru от удаления не только повторяющиеся файлы, но их ссылки. Ты уверен, что не хочу этого, не так ли?

+

Что определяет, какие файлы ссылки и какие файлы являются дубликатами сначала свою папку государства. Файл с ссылкой папка всегда будет ссылка в дубликат группы. Если все файлы из обычной папки, размер определить, какой файл будет ведения дубликат группы. dupeGuru предполагает, что вы всегда хотите сохранить крупнейших файл, так что крупных файлов займет исходное положение.

+

Вы можете изменить ссылку файл группы вручную. Для этого выберите дубликат файла, который вы хотите продвигать на ссылку, и нажмите на кнопку Действия -> Добавить выбранной ссылки.

+
+
+

Просмотр результатов

+

Хотя вы можете просто нажать на Правка -> Выделить все, а затем Действия -> Отправить Помечено в Корзину быстро удалить все дубликаты файлов в результатах, всегда рекомендуется пересмотреть все дубликаты перед удаляя их.

+

Чтобы помочь вам обзор результатов, вы можете вызвать панель Подробнее. Эта панель показывает все детали выбранного файла, а также подробности своей ссылки в. Это очень удобно, чтобы быстро определить, если дубликат действительно дубликат. Вы также можете дважды щелкнуть по файлу, чтобы открыть его и связанные с ним приложения.

+

Если у вас есть больше ложных дубликатов, чем правда дубликатов (Если Ваш фильтр жесткость очень низкая), лучший способ продолжить бы пересмотреть дубликатов, знак истинного дубликаты и нажмите Действия -> Отправить Помечено в Корзину . Если у вас есть более верно, чем ложных дубликатов дубликатов, вместо этого можно пометить все файлы, которые являются ложными дубликатов, а также использовать Действия -> Удалить Помеченные от результатов.

+
+
+

Маркировка и выбор

+

Отмеченные дубликат двух экземплярах с небольшой флажок рядом с ним, имеющие галочки. Выбран дубликат дубликата быть выделены. Несколько действий, выбор может быть выполнена в dupeGuru стандартным образом (Shift / Command / Control клик). Вы можете переключать знак состояние всех выбранных дубликаты «, нажав пространстве.

+
+
+

Показать только обманутые

+

Когда этот режим включен, дубликаты отображаются без их соответствующего файла справки. Вы можете выбрать, марка и сортировать этот список, как и в обычном режиме.

+

DupeGuru результаты, когда в нормальном режиме, сортируются в соответствии с дубликат группы „ссылке на файл. Это означает, что если вы хотите, например, чтобы отметить все дубликаты «EXE» расширением, вы не можете просто сортировать результаты по «Вид», чтобы иметь все EXE дубликатов вместе, потому что группа может состоять из более чем одного типа файлов . Вот где обманутые Только режим вступает в игру. Чтобы отметить все ваши «EXE» дубликаты, вы просто должны:

+
    +
  • Включить обманутые Только режим.
  • +
  • Добавить «Вид» колонку «Столбцы» меню.
  • +
  • Нажмите на том, что «Вид» колонки, чтобы отсортировать список по типу.
  • +
  • Найдите первый дубликат с «EXE» рода.
  • +
  • Выберите его.
  • +
  • Прокрутите список, чтобы найти последнего дубликата с «EXE» рода.
  • +
  • Удерживайте Shift и щелкните по нему.
  • +
  • Нажмите Space, чтобы пометить все выбранные дубликатов.
  • +
+
+
+

Дельта значения

+

Если включить этот переключатель на некоторые столбцы будут отображать значение по отношению к дубликата ссылке, а не абсолютные значения. Эти дельты значения также будут отображаться в разные цвета, чтобы вы могли заметить их легко. Например, если дубликат 1,2 Мб и свою ссылку в 1,4 Мб, размер столбец отображает -0,2 Мб.

+
+
+

Только обманутые и Дельта значения

+

Только обманутые режиме раскрыть свою истинную силу, когда вы используете его с Делта Значения переключатель включен. Когда вы включите его, относительные значения будет отображаться вместо абсолютных. Так что если, например, вы хотите удалить из результатов все дубликаты, которые являются более 300 Кб от их ссылке, вы можете отсортировать дубликаты только результаты по размеру, выберите все дубликаты при -300 в столбце Размер, удалять их, , а затем сделать то же самое повторяет более 300 в нижней части списка.

+

Вы можете также использовать его для изменения ссылки приоритет повторяющиеся список. Когда вы делаете свежие сканирования, если Есть нет ссылки папки, ссылке на файл каждой группы является самой большой файл. Если вы хотите изменить, что, например, в последней модификации время, вы можете отсортировать дубликаты только результаты по времени модификации в убывания порядке выберите все дубликаты со временем изменения дельты значение больше 0 и нажмите Убедитесь, выбранной ссылки. Причина, почему вы должны сделать порядок сортировки по убыванию, потому что если 2 файла среди таких же дубликат группы выбираются при нажатии на Сделать выбранной ссылки, только первый из списка будут сделаны ссылки, другие будут проигнорированы . И так как вы хотите Последнее изменение файла для ссылки, имеющие порядок сортировки по убыванию уверяет вас, что первым пунктом в списке будет последнего изменения.

+
+

План

+

Add «Non-numerical delta» information.

+
+
+
+

Фильтрация

+

dupeGuru поддерживает после сканирования, фильтрации. С его помощью вы можете сузить результаты, чтобы вы могли выполнять действия, на подмножества. Например, вы можете легко пометить все дубликаты с их имя файла, содержащего «копировать» из результатов с помощью фильтра.

+
+

План

+

Qt has a toolbar search field now, not a menu item.

+
+

Windows: Для использования функции фильтрации, нажмите на Действия -> Применить фильтр, запишите фильтр, который вы хотите применить и нажмите ОК. Чтобы вернуться к нефильтрованное результаты, нажмите на Действия -> Отменить фильтр.

+

Mac OS X: Для использования функции фильтрации, тип фильтра в «Фильтр» поле поиска на панели инструментов. Чтобы вернуться к нефильтрованное результате, очистите поле, или нажмите на кнопку «X».

+

В простом режиме (режим по умолчанию), что вы вводите в качестве фильтра строку, используемую для выполнения фактической фильтрации, за исключением одной маски: *. Таким образом, если вы введете «[*]» как ваш фильтр, он будет соответствовать что-нибудь с [] скобках в нем, все, что между этими скобками.

+

Для более продвинутых фильтров, вы можете включить «Использование регулярных выражений при фильтрации» на. Функция фильтрации будет использовать регулярные выражения. Регулярное выражение языка для согласования текста. Объясняя их выходит за рамки этого документа. Хорошее место для начала обучения он regular_expressions.info <http://www.regular-expressions.info>_.

+

Матчи не чувствительны к регистру, в простых и регулярных выражений режиме.

+

Для фильтра, чтобы соответствовать, регулярное выражение не обязательно должно совпадать целый файл, он просто обязан содержать в цепочку, соответствующую выражению.

+

Вы могли заметить, что не все дубликаты в результате будут соответствовать вашим фильтром. Это потому, что как только одна копия в матчах группового фильтра, то вся группа останется в результатах, таким образом Вы можете иметь более четкое представление о дубликата контексте. Тем не менее, не соответствующие дубликаты в «ссылку режиме». Таким образом, можно выполнять действия, как Марк все и обязательно только знак фильтруется дубликатов.

+
+
+

Действие меню

+
    +
  • Открытый черный список: Удалите все игнорируют матчи вы добавили. Вы должны начать новый поиск вновь очищается список игнорируемых чтобы быть эффективными.
  • +
  • Экспорт результатов в XHTML: Возьмите текущие результаты, а также создавать файл XHTML из него. Столбцов, которые видны при нажатии на эту кнопку будет столбцов в файле XHTML. Файл автоматически откроется в браузере по умолчанию.
  • +
  • Отправить Помечено в корзину: Отправить все отмеченные дубликаты, мусор, это очевидно.
  • +
  • Удалить Помеченные и замена с Жесткие: Передает все отмеченные дубликаты, мусор, но после того, как сделали это, удаленные файлы заменяются жестких ссылку к ссылке на файл. (Только для OS X и Linux)
  • +
  • Перемещение Помечено в …: запросит назначения, а затем переместить все отмеченные файлы в том, что назначения. Путь исходного файла может быть воссоздан в пункт назначения, в зависимости от «Копирование и перемещение» предпочтения.
  • +
  • Скопируйте Помечено в …: запросит у вас место, а затем скопировать все выбранные файлы к этому пункту назначения. Путь исходного файла может быть воссоздан в пункт назначения, в зависимости от «Копирование и перемещение» предпочтения.
  • +
  • Удалить Помеченные из результатов: Удалить все отмеченные дубликатов из результата поиска. Сами файлы не будут затронуты и останутся, где они.
  • +
  • Удалить выбранные из результатов: Удалить все выбранные дубликатов из результата поиска. Обратите внимание, что все выбранные файлы ссылки будут игнорироваться, только дубликаты могут быть удалены с этим действием.
  • +
  • Сделать Выбранный Справка: Содействие все выбранные дубликатов ссылки. Если дубликат частью группы, имеющей ссылке на файл ближайшие из ссылки папки (в синий цвет), не будут приняты меры для этого дубликат. Если более чем один дубликат среди той же группы выбраны, только первый из каждой группы будет поощряться.
  • +
  • Добавить выбранные в черный список: Это сначала удаляет все выбранные дубликаты из результатов, а затем добавить матча, которые дублируют и опорный ток в черный список. Этот матч не придет снова в дальнейшей проверки. Копировать себя и, возможно, вернется, но он будет искаться в другой ссылке на файл. Вы можете очистить список игнорируемых с Открытый черный список команды.
  • +
  • Открытое Выбранный с приложений по умолчанию: Откройте файл с помощью приложения, связанного с типом выбранного файла.
  • +
  • Показать Выбранный в Finder-е: Откройте папку, содержащую выбранный файл.
  • +
  • Вызов специальной команды: Вызывает внешнюю программу вы установили в настройках с использованием выделенного фрагмента в качестве аргументов в вызове.
  • +
  • Переименования выбрано: Запрашивает новое имя, а затем переименовать выбранный файл.
  • +
+
+

План

+

Add Move and iPhoto/iTunes warning

+
+
+

План

+

Add «Deletion Options» section.

+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/ru/search.html b/help/ru/search.html new file mode 100644 index 00000000..b6169ec7 --- /dev/null +++ b/help/ru/search.html @@ -0,0 +1,78 @@ + + + + + + + + Поиск — Документация dupeGuru 4.0.3 + + + + + + + + + + + + + + + + + + + + +
+ + +

Поиск

+
+ +

+ Для работы поиска включите JavaScript в браузере. +

+
+

+ Здесь можно делать поиск по всем разделам этой документации. Введите ключевые слова в текстовое поле и нажмите кнопку «искать». Внимание: будут найдены только те страницы, в которых есть все указанные слова. Страницы, где есть только часть этих слов, отобраны не будут. +

+
+ + + +
+ +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/help/ru/searchindex.js b/help/ru/searchindex.js new file mode 100644 index 00000000..0233f5b8 --- /dev/null +++ b/help/ru/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["changelog","faq","folders","index","preferences","quick_start","reprioritize","results"],envversion:53,filenames:["changelog.rst","faq.rst","folders.rst","index.rst","preferences.rst","quick_start.rst","reprioritize.rst","results.rst"],objects:{},objnames:{},objtypes:{},terms:{"32bit":0,"64bit":0,"\u0430":[1,2,5,6,7],"\u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d":[1,4,7],"\u0430\u0432":1,"\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a":[2,6,7],"\u0430\u043b\u0444\u0430\u0432\u0438\u0442\u043d":3,"\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d":2,"\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442":[6,7],"\u0430\u0441":1,"\u0431":1,"\u0431\u0435\u0437":[3,5,7],"\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d":7,"\u0431\u043b\u0438\u0436\u0430\u0439\u0448":7,"\u0431\u043e\u043b":[2,6,7],"\u0431\u043e\u043b\u044c\u0448":[1,7],"\u0431\u0440\u0430\u0443\u0437\u0435\u0440":7,"\u0431\u0443\u0434\u0435\u0442":[1,2,4,6,7],"\u0431\u0443\u0434\u0443\u0442":[2,4,6,7],"\u0431\u0443\u043a\u0432":1,"\u0431\u044b":[1,7],"\u0431\u044b\u043b":[1,4,6],"\u0431\u044b\u0441\u0442\u0440":[3,7],"\u0431\u044b\u0442":[1,2,3,4,7],"\u0432":[2,4,5,6,7],"\u0432\u0430\u0436\u043d":6,"\u0432\u0430\u043c":[1,2,3,6,7],"\u0432\u0430\u0440\u0438\u0430\u043d\u0442":6,"\u0432\u0430\u0441":[1,4,7],"\u0432\u0430\u0448":[1,3,4,5,6,7],"\u0432\u0432\u0435\u0434\u0435\u0442":7,"\u0432\u0432\u0435\u0441\u0442":2,"\u0432\u0432\u043e\u0434":7,"\u0432\u0435":7,"\u0432\u0435\u0434\u0435\u043d":7,"\u0432\u0435\u0440\u043d":7,"\u0432\u0435\u0440\u043d\u0435\u0442":7,"\u0432\u0435\u0440\u043d\u0443\u0442":7,"\u0432\u0435\u0440\u043e\u044f\u0442\u043d":1,"\u0432\u0435\u0440\u0441":3,"\u0432\u0435\u0441\u0442":4,"\u0432\u0437\u0433\u043b\u044f\u043d\u0443\u0442":3,"\u0432\u0438\u0434":[1,2,4,7],"\u0432\u0438\u0434\u043d":7,"\u0432\u043a\u043b\u044e\u0447":[1,2,4,7],"\u0432\u043a\u043b\u044e\u0447\u0435\u043d":2,"\u0432\u043c\u0435\u0441\u0442":[1,7],"\u0432\u043d\u0435\u0448\u043d":[4,7],"\u0432\u043d\u0438\u043c\u0430\u043d":7,"\u0432\u043d\u043e\u0432":7,"\u0432\u043e":[1,4,6],"\u0432\u043e\u0437\u043c\u043e\u0436\u043d":[4,7],"\u0432\u043e\u0437\u044c\u043c":7,"\u0432\u043e\u043e\u0431\u0449":4,"\u0432\u043e\u043f\u0440\u043e\u0441":3,"\u0432\u043e\u0441\u0441\u043e\u0437\u0434\u0430":[4,7],"\u0432\u043e\u0442":[4,7],"\u0432\u043f\u043b\u043e\u0442":4,"\u0432\u0440\u0435\u043c":7,"\u0432\u0440\u0435\u043c\u0435\u043d":[1,7],"\u0432\u0440\u0443\u0447\u043d":[1,7],"\u0432\u0441\u0435":[2,4,5,6,7],"\u0432\u0441\u0435\u0433\u0434":[1,7],"\u0432\u0441\u0435\u0445":[4,7],"\u0432\u0441\u043f\u043b\u044b\u0432\u0430":2,"\u0432\u0441\u0442\u0443\u043f\u0430":[6,7],"\u0432\u0441\u044f":7,"\u0432\u0442\u043e\u0440":6,"\u0432\u044b":[1,2,3,4,5,6,7],"\u0432\u044b\u0431\u0435\u0440":[2,6,7],"\u0432\u044b\u0431\u0438\u0440\u0430":[2,7],"\u0432\u044b\u0431\u043e\u0440":3,"\u0432\u044b\u0431\u0440\u0430":[1,2,4,5,6,7],"\u0432\u044b\u0434\u0435\u043b":[1,5,7],"\u0432\u044b\u0434\u0435\u043b\u0435\u043d":[4,7],"\u0432\u044b\u0437":[4,7],"\u0432\u044b\u0437\u0432\u0430":[6,7],"\u0432\u044b\u0437\u043e\u0432":7,"\u0432\u044b\u0437\u044b\u0432\u0430":[4,7],"\u0432\u044b\u043f\u0430\u0434\u0430":6,"\u0432\u044b\u043f\u043e\u043b\u043d":7,"\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d":7,"\u0432\u044b\u043f\u043e\u043b\u043d\u044f":[1,7],"\u0432\u044b\u0440\u0430\u0436\u0435\u043d":[4,7],"\u0432\u044b\u0441\u0448":6,"\u0432\u044b\u0445\u043e\u0434":[4,7],"\u0432\u044b\u0448":5,"\u0433\u0430\u043b\u043e\u0447\u043a":7,"\u0433\u0430\u043b\u0441\u0442\u0443\u043a":6,"\u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440":1,"\u0433\u0434\u0435":7,"\u0433\u0438\u0431\u043a":1,"\u0433\u043e\u0441\u0443\u0434\u0430\u0440\u0441\u0442\u0432":[3,7],"\u0433\u0440\u0443\u043f\u043f":[1,2,3,4,5,6],"\u0433\u0440\u0443\u043f\u043f\u043e\u0432":7,"\u0434\u0430\u0432\u0430":[1,5],"\u0434\u0430\u0435\u0442":1,"\u0434\u0430\u043b":6,"\u0434\u0430\u043b\u044c\u043d":7,"\u0434\u0432\u0430":6,"\u0434\u0432\u0430\u0436\u0434":7,"\u0434\u0432\u0443\u0445":7,"\u0434\u0435\u0439\u0441\u0442\u0432":[1,3,4,5,6],"\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d":[5,7],"\u0434\u0435\u043b":1,"\u0434\u0435\u043b\u0430":[5,6,7],"\u0434\u0435\u043b\u0442":7,"\u0434\u0435\u043b\u044c\u0442":[3,6],"\u0434\u0435\u0440\u0436\u0430":1,"\u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440":4,"\u0434\u0435\u0442\u0430":7,"\u0434\u0438\u0430\u043b\u043e\u0433":6,"\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440":4,"\u0434\u043b\u044f":[1,2,3,4,5,6,7],"\u0434\u043e":4,"\u0434\u043e\u0431\u0430\u0432":[1,2,4,7],"\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d":[2,4,5,6],"\u0434\u043e\u0431\u0430\u0432\u043b\u044f":[1,2],"\u0434\u043e\u0432\u043e\u043b\u044c\u043d":2,"\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442":[1,4,7],"\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446":3,"\u0434\u043e\u043b\u0436":6,"\u0434\u043e\u043b\u0436\u043d":[1,4,7],"\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d":6,"\u0434\u043e\u0441\u0442\u0443\u043f":1,"\u0434\u043e\u0441\u0442\u0443\u043f\u043d":6,"\u0434\u0440\u0443\u0433":[2,7],"\u0434\u0443\u0431\u043b\u0438\u043a\u0430\u0442":[2,3,4,5],"\u0434\u0443\u0431\u043b\u0438\u0440":7,"\u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430":[3,4,5],"\u0434\u0443\u043c\u0430":1,"\u0435":[5,7],"\u0435\u0433":[2,3,4,6,7],"\u0435\u0433\u043e":7,"\u0435\u0441\u043b":[1,2,4,6,7],"\u0435\u0441\u043b\u0438":[1,2,3,4,5,6,7],"\u0435\u0441\u0442":[4,6,7],"\u0435\u0441\u0442\u044c":[1,4,5,7],"\u0435\u0449":1,"\u0436\u0435":[1,2,4,7],"\u0436\u0435\u0441\u0442\u043a":7,"\u0436\u0435\u0441\u0442\u043a\u043e\u0441\u0442":7,"\u0437\u0430":[4,7],"\u0437\u0430\u0432\u0435\u0440\u0448":5,"\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d":7,"\u0437\u0430\u0432\u0438\u0441\u0438\u043c":7,"\u0437\u0430\u0434\u0430\u0432\u0430":3,"\u0437\u0430\u0439\u043c\u0435\u0442":7,"\u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430":6,"\u0437\u0430\u043a\u043b\u044e\u0447":4,"\u0437\u0430\u043a\u043b\u044e\u0447\u0430":1,"\u0437\u0430\u043c":7,"\u0437\u0430\u043c\u0435\u043d":4,"\u0437\u0430\u043c\u0435\u043d\u044f":7,"\u0437\u0430\u043c\u0435\u0442":7,"\u0437\u0430\u043f\u0438\u0448":7,"\u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b":4,"\u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430":7,"\u0437\u0430\u043f\u0440\u043e\u0441":[4,7],"\u0437\u0430\u043f\u0443\u0441\u043a":5,"\u0437\u0430\u043f\u0443\u0441\u043a\u0430":2,"\u0437\u0430\u043f\u0443\u0441\u0442":1,"\u0437\u0430\u0442":[1,5,6,7],"\u0437\u0430\u0442\u0440\u043e\u043d\u0443\u0442":7,"\u0437\u0434\u0435":6,"\u0437\u043d\u0430\u043a":[5,7],"\u0437\u043d\u0430\u043a\u043e\u043c":1,"\u0437\u043d\u0430\u0447\u0435\u043d":3,"\u0438":[1,2,3,4,5,6],"\u0438\u0433\u043d\u043e\u0440\u0438\u0440":7,"\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430":[4,7],"\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u043c":7,"\u0438\u0433\u0440":7,"\u0438\u0433\u0440\u0430":6,"\u0438\u0434\u0435":3,"\u0438\u0437":[2,5,7],"\u0438\u0437\u043c\u0435\u043d":[5,6,7],"\u0438\u0437\u043c\u0435\u043d\u0435\u043d":[5,6,7],"\u0438\u0437\u0443\u0447\u0435\u043d":5,"\u0438\u043b":[1,4,5,6,7],"\u0438\u043c":[1,4,6,7],"\u0438\u043c\u0435\u0435\u0442":[1,6,7],"\u0438\u043c\u0435\u0442":7,"\u0438\u043c\u0435\u044e\u0442":6,"\u0438\u043c\u0435\u044e\u0449":7,"\u0438\u043c\u044f":6,"\u0438\u043d\u0432\u0430\u043b\u0438\u0434":5,"\u0438\u043d\u0434\u0435\u043a\u0441\u043d":4,"\u0438\u043d\u043e\u0433\u0434":6,"\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442":7,"\u0438\u0441\u043a\u0430":7,"\u0438\u0441\u043a\u043b\u044e\u0447":2,"\u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d":[4,7],"\u0438\u0441\u043f\u043e\u043b\u043d\u044f":4,"\u0438\u0441\u043f\u043e\u043b\u044c\u0437":6,"\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430":[2,3,6,7],"\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d":[2,4,7],"\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c":7,"\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442":7,"\u0438\u0441\u043f\u0440\u0430\u0432":1,"\u0438\u0441\u0442\u0438\u043d":7,"\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a":4,"\u0438\u0441\u0445\u043e\u0434\u043d":[1,4,7],"\u0438\u0442\u043e\u0433":[1,2],"\u0438\u0445":[1,2,4,7],"\u0438\u0449\u0435\u0442":3,"\u043a":[1,2,4,6,7],"\u043a\u0430\u0432\u044b\u0447\u043a":4,"\u043a\u0430\u0436\u0434":[2,5,6,7],"\u043a\u0430\u043a":[1,4,6,7],"\u043a\u0430\u043f\u043b":5,"\u043a\u0430\u0442\u0430\u043b\u043e\u0433":[2,4],"\u043a\u0430\u0442\u0435\u0433\u043e\u0440":6,"\u043a\u0430\u0447\u0435\u0441\u0442\u0432":[1,7],"\u043a\u0431":7,"\u043a\u043b\u0430\u0432\u0438\u0448":1,"\u043a\u043b\u0438\u043a":7,"\u043a\u043d\u043e\u043f\u043a":[1,2,5,6,7],"\u043a\u043e\u0433\u0434":[1,2,4,6,7],"\u043a\u043e\u043b\u043e\u043d\u043a":[1,7],"\u043a\u043e\u043c\u0430\u043d\u0434":[4,7],"\u043a\u043e\u043c\u0430\u043d\u0434\u043d":[1,4],"\u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0442":4,"\u043a\u043e\u043d\u0435\u0447\u043d":[1,2,4],"\u043a\u043e\u043d\u0442\u0430\u043a\u0442":1,"\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442":7,"\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c\u043d":1,"\u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442":4,"\u043a\u043e\u043f":7,"\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430":7,"\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d":[4,7],"\u043a\u043e\u0440\u0437\u0438\u043d":[5,7],"\u043a\u043e\u0440\u043d\u0435\u0432":4,"\u043a\u043e\u0442\u043e\u0440":[2,4,5,6,7],"\u043a\u0440\u0430\u0439\u043d":1,"\u043a\u0440\u0430\u0441\u0438\u0432":4,"\u043a\u0440\u0438\u0442\u0435\u0440":6,"\u043a\u0440\u0443\u043f\u043d":[6,7],"\u043b\u0435\u0433\u043a":[1,3,7],"\u043b\u0438":7,"\u043b\u0438\u0431":[1,5],"\u043b\u043e\u0436\u043d":[5,7],"\u043b\u0443\u0447\u0448":7,"\u043b\u044e\u0431":2,"\u043c\u0430\u0440\u043a":7,"\u043c\u0430\u0440\u043a\u0438\u0440\u043e\u0432\u043a":3,"\u043c\u0430\u0441\u043a":7,"\u043c\u0430\u0442\u0447":[1,7],"\u043c\u0431":7,"\u043c\u0435\u0436\u0434":7,"\u043c\u0435\u043d":[2,3,4,6],"\u043c\u0435\u0440":[1,7],"\u043c\u0435\u0441\u0442":[4,7],"\u043c\u0435\u0442\u043e\u0434":5,"\u043c\u043d\u043e\u0433":[5,6],"\u043c\u043e\u0433\u043b":7,"\u043c\u043e\u0433\u0443\u0442":7,"\u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446":7,"\u043c\u043e\u0436\u0435\u0442":[2,3,4,5,6,7],"\u043c\u043e\u0436\u043d":[2,4,7],"\u043c\u043e\u0449\u043d":6,"\u043c\u0443\u0441\u043e\u0440":7,"\u043c\u044b":1,"\u043d\u0430":[1,2,3,4,5,6,7],"\u043d\u0430\u0434":1,"\u043d\u0430\u0436\u0430":[1,2,7],"\u043d\u0430\u0436\u0430\u0442":[2,7],"\u043d\u0430\u0436\u043c":[1,2,5,6,7],"\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d":[4,7],"\u043d\u0430\u0439\u0434":[2,7],"\u043d\u0430\u0439\u0442":[2,7],"\u043d\u0430\u043b\u0438\u0447":7,"\u043d\u0430\u043f\u0438\u0441\u0430":[1,4],"\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440":[4,6,7],"\u043d\u0430\u0441":1,"\u043d\u0430\u0441\u043b\u0435\u0434":2,"\u043d\u0430\u0441\u0442\u0440\u043e":1,"\u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a":5,"\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a":[1,5,7],"\u043d\u0430\u0445\u043e\u0434":2,"\u043d\u0430\u0447\u0430":[3,4,5,7],"\u043d\u0435":[2,4,6,7],"\u043d\u0435\u0431\u043e\u043b\u044c\u0448":7,"\u043d\u0435\u0433":[2,7],"\u043d\u0435\u043a\u043e\u0442\u043e\u0440":[1,7],"\u043d\u0435\u043c":7,"\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c":4,"\u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d":[2,4],"\u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d":6,"\u043d\u0435\u043f\u0440\u0438\u044f\u0442\u043d":1,"\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a":[1,5,6,7],"\u043d\u0435\u0442":[5,7],"\u043d\u0435\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430":7,"\u043d\u0438":4,"\u043d\u0438\u0431\u0443\u0434":7,"\u043d\u0438\u0436":[2,6],"\u043d\u0438\u0436\u043d":7,"\u043d\u0438\u0437\u043a":[1,7],"\u043d\u0438\u043a\u0430\u043a":1,"\u043d\u0438\u043a\u043e\u0433\u0434":[1,2,7],"\u043d\u0438\u043c":7,"\u043d\u0438\u0445":[1,2,5],"\u043d\u043e":[6,7],"\u043d\u043e\u0432":[2,7],"\u043d\u043e\u043c\u0435\u0440":[4,6],"\u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d":[2,7],"\u043d\u0443":4,"\u043e":[1,3,5],"\u043e\u0431":1,"\u043e\u0431\u0437\u043e\u0440":7,"\u043e\u0431\u043c\u0430\u043d\u0443\u0442":[1,2,3,4,6],"\u043e\u0431\u043d\u043e\u0432\u043b":3,"\u043e\u0431\u0440\u0430\u0437":[1,7],"\u043e\u0431\u0440\u0430\u0442":7,"\u043e\u0431\u0443\u0447\u0435\u043d":[4,7],"\u043e\u0431\u0445\u043e\u0434\u043d":1,"\u043e\u0431\u044a\u044f\u0441\u043d":[4,7],"\u043e\u0431\u044b\u0447\u043d":7,"\u043e\u0431\u044f\u0437\u0430":7,"\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d":7,"\u043e\u0434\u0438\u043d":[1,2,7],"\u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432":[6,7],"\u043e\u0434\u043d":[1,2,7],"\u043e\u0434\u043d\u0430\u043a":1,"\u043e\u0437\u043d\u0430\u0447\u0430":[1,6,7],"\u043e\u043a":7,"\u043e\u043a\u0430\u043d\u0447\u0438\u0432\u0430":6,"\u043e\u043a\u043d":[2,5,7],"\u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d":1,"\u043e\u043d":[4,7],"\u043e\u043d\u0430":1,"\u043e\u043f\u0435\u0440\u0430\u0446":4,"\u043e\u043f\u043e\u0440\u043d":7,"\u043e\u043f\u0440\u0435\u0434\u0435\u043b":[1,6,7],"\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f":[1,4,7],"\u043e\u043f\u0446":[1,4],"\u043e\u0441\u0432\u043e":3,"\u043e\u0441\u043d\u043e\u0432\u043d":5,"\u043e\u0441\u0442\u0430\u043b\u044c\u043d":5,"\u043e\u0441\u0442\u0430\u043d\u0435\u0442":7,"\u043e\u0441\u0442\u0430\u043d\u0443\u0442":7,"\u043e\u0442":7,"\u043e\u0442\u043a\u043b\u044e\u0447":7,"\u043e\u0442\u043a\u0440":7,"\u043e\u0442\u043a\u0440\u043e\u0435\u0442":7,"\u043e\u0442\u043a\u0440\u043e\u0439\u0442":7,"\u043e\u0442\u043a\u0440\u044b\u0442":7,"\u043e\u0442\u043c\u0435\u043d":[1,7],"\u043e\u0442\u043c\u0435\u0442":[4,5,7],"\u043e\u0442\u043c\u0435\u0447\u0435\u043d":[1,7],"\u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d":[4,7],"\u043e\u0442\u043d\u043e\u0448\u0435\u043d":7,"\u043e\u0442\u043e\u0431\u0440\u0430":6,"\u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430":7,"\u043e\u0442\u043f\u0440\u0430\u0432":[5,6,7],"\u043e\u0442\u043f\u0440\u0430\u0432\u043a":1,"\u043e\u0442\u043f\u0440\u0430\u0432\u043b":4,"\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f":1,"\u043e\u0442\u043f\u0443\u0441\u0442":6,"\u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430":7,"\u043e\u0442\u0441\u0442\u0443\u043f":[5,7],"\u043e\u0442\u0441\u0447\u0435\u0442":1,"\u043e\u0447\u0435\u0432\u0438\u0434\u043d":7,"\u043e\u0447\u0435\u043d":[1,4,7],"\u043e\u0447\u0438\u0441\u0442":7,"\u043e\u0447\u0438\u0449\u0430":7,"\u043f\u0430\u043d\u0435\u043b":[4,7],"\u043f\u0430\u043f\u043a":[3,4,6,7],"\u043f\u0430\u043f\u043e\u043a":[2,4,5],"\u043f\u0435\u0440\u0432":[1,2,3,6,7],"\u043f\u0435\u0440\u0435\u0434":7,"\u043f\u0435\u0440\u0435\u0434\u0430":7,"\u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430":7,"\u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d":7,"\u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430":7,"\u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b":7,"\u043f\u0435\u0440\u0435\u043c\u0435\u043d":1,"\u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442":[1,7],"\u043f\u0435\u0440\u0435\u043c\u0435\u0449":4,"\u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430":4,"\u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d":[1,4,7],"\u043f\u0435\u0440\u0435\u0441\u043c\u043e\u0442\u0440\u0435\u0442":7,"\u043f\u0435\u0440\u0435\u0442\u0430\u0449":[2,5,6],"\u043f\u0435\u0440\u0435\u0447\u0435\u043d":6,"\u043f\u043e":[1,2,5,6,7],"\u043f\u043e\u0431\u0435\u0434":6,"\u043f\u043e\u0432\u0442\u043e\u0440\u043d":[1,3,4],"\u043f\u043e\u0432\u0442\u043e\u0440\u044f":7,"\u043f\u043e\u0434":7,"\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430":7,"\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a":1,"\u043f\u043e\u0434\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432":7,"\u043f\u043e\u0434\u043e\u0436\u0434":5,"\u043f\u043e\u0434\u043f\u0430\u043f\u043a":2,"\u043f\u043e\u0434\u0440\u043e\u0431\u043d":7,"\u043f\u043e\u0437\u0432\u043e\u043b\u044c\u0442":1,"\u043f\u043e\u0437\u0432\u043e\u043b\u044f":[1,6],"\u043f\u043e\u0437\u0438\u0446":[2,6],"\u043f\u043e\u0438\u0441\u043a":[3,7],"\u043f\u043e\u043a":5,"\u043f\u043e\u043a\u0430\u0436\u0435\u0442":7,"\u043f\u043e\u043a\u0430\u0437\u0430":3,"\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430":7,"\u043f\u043e\u043b":7,"\u043f\u043e\u043b\u0435\u0437\u043d":4,"\u043f\u043e\u043b\u043d":4,"\u043f\u043e\u043b\u043e\u0436\u0435\u043d":[1,7],"\u043f\u043e\u043b\u0443\u0447":[1,5],"\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a":4,"\u043f\u043e\u043c\u0435\u0442":[1,7],"\u043f\u043e\u043c\u0435\u0447":[1,5,7],"\u043f\u043e\u043c\u0435\u0447\u0435\u043d":7,"\u043f\u043e\u043c\u043e\u0436":1,"\u043f\u043e\u043c\u043e\u0436\u0435\u0442":3,"\u043f\u043e\u043c\u043e\u0447":7,"\u043f\u043e\u043c\u043e\u0449":[1,5,7],"\u043f\u043e\u043e\u0449\u0440\u044f":7,"\u043f\u043e\u0440\u044f\u0434\u043a":7,"\u043f\u043e\u0440\u044f\u0434\u043e\u043a":[6,7],"\u043f\u043e\u0441\u043b":[1,4,7],"\u043f\u043e\u0441\u043b\u0435\u0434\u043d":[2,3,7],"\u043f\u043e\u0441\u043c\u043e\u0442\u0440":5,"\u043f\u043e\u0441\u044b\u043b\u0430":1,"\u043f\u043e\u0442":[1,4,7],"\u043f\u043e\u0447":7,"\u043f\u043e\u044d\u0442":1,"\u043f\u043e\u044f\u0432":2,"\u043f\u0440\u0430\u0432":[1,4,6],"\u043f\u0440\u0430\u0432\u0434":7,"\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d":1,"\u043f\u0440\u0430\u0432\u043a":7,"\u043f\u0440\u0435\u0434\u043b\u043e\u0436":2,"\u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0442":7,"\u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430":7,"\u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0435\u043d":[3,7],"\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d":7,"\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f":7,"\u043f\u0440\u0435\u0436\u0434":2,"\u043f\u0440\u0438":[1,2,4,7],"\u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d":6,"\u043f\u0440\u0438\u0432\u0435\u0441\u0442":[1,6],"\u043f\u0440\u0438\u0434\u0435\u0442":[1,7],"\u043f\u0440\u0438\u043b\u043e\u0436":4,"\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d":[4,7],"\u043f\u0440\u0438\u043c\u0435\u043d":7,"\u043f\u0440\u0438\u043c\u0435\u0440":[1,4],"\u043f\u0440\u0438\u043d\u044f\u0442":7,"\u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442":[3,7],"\u043f\u0440\u0438\u0447\u0438\u043d":7,"\u043f\u0440\u043e\u0431\u0435\u043b":[1,4],"\u043f\u0440\u043e\u0431\u043b\u0435\u043c":1,"\u043f\u0440\u043e\u0432\u0435\u0440":4,"\u043f\u0440\u043e\u0432\u0435\u0440\u043a":[2,7],"\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c":7,"\u043f\u0440\u043e\u0434\u0432\u0438\u0433\u0430":[1,7],"\u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442":7,"\u043f\u0440\u043e\u0434\u043e\u043b\u0436":7,"\u043f\u0440\u043e\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430":7,"\u043f\u0440\u043e\u043a\u0440\u0443\u0442":7,"\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440":3,"\u043f\u0440\u043e\u0441\u0442":[2,5,7],"\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432":7,"\u043f\u0440\u043e\u0446\u0435\u0441\u0441":5,"\u043f\u0440\u043e\u0447\u0438\u0442\u0430":[1,5],"\u043f\u0440\u044f\u043c":2,"\u043f\u0443\u043d\u043a\u0442":[2,4,6,7],"\u043f\u0443\u0441\u0442":4,"\u043f\u0443\u0442":[1,4,7],"\u043f\u044b\u0442":4,"\u043f\u044b\u0442\u0430":6,"\u0440\u0430\u0437\u0434\u0435\u043b":3,"\u0440\u0430\u0437\u043b\u0438\u0447\u043d":4,"\u0440\u0430\u0437\u043c\u0435\u0440":[6,7],"\u0440\u0430\u0437\u043d":[5,7],"\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430":1,"\u0440\u0430\u0437\u0440\u0435\u0448\u0430":4,"\u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d":1,"\u0440\u0430\u043c\u043a":[4,7],"\u0440\u0430\u043d":6,"\u0440\u0430\u0441\u043a\u0440":7,"\u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430":4,"\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d":[4,7],"\u0440\u0435\u0433\u0438\u0441\u0442\u0440":7,"\u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d":[4,7],"\u0440\u0435\u0436":[1,7],"\u0440\u0435\u0436\u0438\u043c":[1,7],"\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442":[1,3,5,6],"\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434":7,"\u0440\u043e\u0434":7,"\u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432":3,"\u0440\u0443\u0447\u043a":4,"\u0440\u044f\u0434":7,"\u0441":[1,4,5,6,7],"\u0441\u0430\u043c":[1,7],"\u0441\u0431\u043e\u0440":6,"\u0441\u0432\u0435\u0436":7,"\u0441\u0432\u043e":[2,3,7],"\u0441\u0432\u043e\u0439\u0441\u0442\u0432":6,"\u0441\u0432\u044f\u0437":6,"\u0441\u0432\u044f\u0437\u0430":7,"\u0441\u0434\u0435\u043b\u0430":[4,5,6,7],"\u0441\u0435\u0431":[4,7],"\u0441\u0438\u043b":7,"\u0441\u0438\u043d":[1,7],"\u0441\u0438\u0441\u0442\u0435\u043c":1,"\u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430":2,"\u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d":[1,3,5,7],"\u0441\u043a\u0430\u043d\u0438\u0440\u0443":1,"\u0441\u043a\u0430\u0447\u0430":3,"\u0441\u043a\u043e\u0431\u043a":7,"\u0441\u043a\u043e\u043f\u0438\u0440":7,"\u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430":7,"\u0441\u043b\u0435\u0432":6,"\u0441\u043b\u0435\u0434":[1,6],"\u0441\u043b\u0443\u0447\u0430":[1,4,6],"\u0441\u043c":2,"\u0441\u043c\u0435\u0448\u0438\u0432\u0430":4,"\u0441\u043d\u0430\u0447\u0430":[6,7],"\u0441\u043d\u043e\u0432":7,"\u0441\u043e":[2,7],"\u0441\u043e\u0431":7,"\u0441\u043e\u0432\u043f\u0430\u0434\u0430":[1,7],"\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d":7,"\u0441\u043e\u0434\u0435\u0439\u0441\u0442\u0432":[1,7],"\u0441\u043e\u0434\u0435\u0440\u0436":[2,4],"\u0441\u043e\u0434\u0435\u0440\u0436\u0430":[4,7],"\u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d":3,"\u0441\u043e\u0437\u0434\u0430":1,"\u0441\u043e\u0437\u0434\u0430\u0432\u0430":7,"\u0441\u043e\u043a\u0440\u0430\u0449":4,"\u0441\u043e\u043e\u0431\u0440\u0430\u0436\u0435\u043d":1,"\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432":7,"\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430":[1,7],"\u0441\u043e\u0440\u0442\u0438\u0440":7,"\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430":7,"\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a":[1,6,7],"\u0441\u043e\u0441\u0442\u043e\u044f":7,"\u0441\u043e\u0441\u0442\u043e\u044f\u043d":[2,7],"\u0441\u043e\u0445\u0440\u0430\u043d":[2,3,7],"\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d":[4,7],"\u0441\u043f\u0438\u0441\u043a":[2,6,7],"\u0441\u043f\u0438\u0441\u043e\u043a":[2,6,7],"\u0441\u043f\u043e\u0441\u043e\u0431":[2,7],"\u0441\u043f\u0440\u0430\u0432":6,"\u0441\u043f\u0440\u0430\u0432\u043a":[1,2,5,6,7],"\u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430":4,"\u0441\u0440\u0430\u0437":1,"\u0441\u0440\u0435\u0434":7,"\u0441\u0441\u044b\u043b\u0430":4,"\u0441\u0441\u044b\u043b\u043a":[1,2,4,5,6,7],"\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d":[5,7],"\u0441\u0442\u0430\u0440\u0442":3,"\u0441\u0442\u043e\u043b\u0431\u0435\u0446":7,"\u0441\u0442\u043e\u043b\u0431\u0446":7,"\u0441\u0442\u0440\u0435\u043b\u043a":6,"\u0441\u0442\u0440\u043e\u043a":[4,7],"\u0441\u0443\u0437":7,"\u0441\u0443\u0449\u0435\u0441\u0442\u0432":[1,4],"\u0441\u0447\u0438\u0442\u0430":4,"\u0442\u0430\u043a":[4,6,7],"\u0442\u0430\u043a\u0436":[4,7],"\u0442\u0430\u043c":1,"\u0442\u0432\u0435\u0440\u0434\u043e\u0441\u0442":1,"\u0442\u0435\u043a\u0441\u0442":7,"\u0442\u0435\u043a\u0443\u0449":7,"\u0442\u0435\u043c":7,"\u0442\u0438\u043f":7,"\u0442\u043e":[1,2,4,7],"\u0442\u043e\u0433":[4,7],"\u0442\u043e\u0433\u0434":1,"\u0442\u043e\u043a":[1,7],"\u0442\u043e\u043b\u044c\u043a":[1,2,3,4,5,6],"\u0442\u043e\u043c":7,"\u0442\u043e\u0442":4,"\u0442\u0440\u0435\u0431":6,"\u0442\u0440\u044e\u043a":6,"\u0442\u044b":7,"\u0443":[4,7],"\u0443\u0431\u0435\u0434":[1,5,7],"\u0443\u0431\u044b\u0432\u0430\u043d":7,"\u0443\u0432\u0435\u0440":[1,2,5,7],"\u0443\u0432\u0435\u0440\u044f":7,"\u0443\u0432\u0438\u0434\u0435\u0442":4,"\u0443\u0434\u0430\u043b":[2,4,5,7],"\u0443\u0434\u0430\u043b\u0435\u043d":[4,7],"\u0443\u0434\u0430\u043b\u044f":[1,2,7],"\u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430":7,"\u0443\u0434\u043e\u0431\u043d":7,"\u0443\u0436":4,"\u0443\u0437\u043d\u0430":5,"\u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b":3,"\u0443\u043c\u043d":6,"\u0443\u043c\u043e\u043b\u0447\u0430\u043d":[2,5,7],"\u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430":2,"\u0443\u0441\u0442\u0430\u043d\u043e\u0432":[1,4,7],"\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b":[2,4],"\u0443\u0442\u0438\u043b\u0438\u0442":1,"\u0444\u0430\u0439\u043b":[2,3,4,5,6,7],"\u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a":7,"\u0444\u0438\u043a\u0441\u0430\u0446":1,"\u0444\u0438\u043b\u044c\u0442\u0440":[1,4,7],"\u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446":[3,4],"\u0444\u043b\u0430\u0436\u043e\u043a":[4,7],"\u0444\u043e\u0440\u043c\u0430\u0442":4,"\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442":7,"\u0444\u0443\u043d\u043a\u0446":7,"\u0445":2,"\u0445\u043e\u0440\u043e\u0448":[3,4,7],"\u0445\u043e\u0442":[1,2,3,7],"\u0445\u043e\u0442\u0435\u043b":1,"\u0445\u043e\u0447":7,"\u0446\u0432\u0435\u0442":7,"\u0446\u0435\u043b":7,"\u0446\u0435\u043d\u043d\u043e\u0441\u0442":6,"\u0446\u0435\u043f\u043e\u0447\u043a":7,"\u0447\u0430\u0441\u0442":[3,5,7],"\u0447\u0435\u043c":[2,7],"\u0447\u0435\u0440\u0435\u0437":[4,6],"\u0447\u0435\u0440\u043d":7,"\u0447\u0435\u0442\u043a":7,"\u0447\u043b\u0435\u043d":1,"\u0447\u0440\u0435\u0437\u0432\u044b\u0447\u0430\u0439\u043d":1,"\u0447\u0442\u0435\u043d":3,"\u0447\u0442\u043e":[2,4,5,6,7],"\u0447\u0442\u043e\u0431":[2,3,4,5,7],"\u0447\u0443\u0432\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d":7,"\u0449\u0435\u043b\u043a\u043d":7,"\u0449\u0435\u043b\u043a\u043d\u0443\u0442":7,"\u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440":7,"\u044d\u043a\u0441\u043f\u043e\u0440\u0442":7,"\u044d\u043b\u0435\u043c\u0435\u043d\u0442":6,"\u044d\u0442":[2,3,4,5,6,7],"\u044d\u0442\u0430":7,"\u044d\u0442\u0438":[4,7],"\u044d\u0442\u043e":[1,2,3,4,5,7],"\u044d\u0442\u043e\u0442":[4,6,7],"\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d":7,"\u044f\u0432\u043b\u044f":[1,4,7],"\u044f\u0432\u043d":2,"\u044f\u0437\u044b\u043a":7,"ale\u0161":0,"case":0,"default":0,"delete":0,"double":0,"export":0,"false":0,"for":0,"i\u0435\u0441\u043b\u0438":1,"interface":0,"long":0,"new":0,"switch":0,"t\u00e4tzner":0,"this":[0,1],"while":0,"with":0,ability:0,about:0,accidental:0,action:0,actions:0,active:0,add:[0,2,7],added:0,adding:0,affected:0,after:0,again:0,alarmed:0,algorithm:0,all:0,allow:0,already:0,also:0,analyzed:0,and:[0,4,7],anh:0,annoyances:0,anymore:0,anyway:0,aperture:[0,2],app:0,application:0,applications:0,applied:0,arbitrary:0,arbysoft:1,arch:0,archive2015:0,are:0,aren:0,armenian:0,ascii:0,asks:0,attribute:0,attributeerror:0,audio:0,auto:0,automatic:0,avoid:0,aware:0,back:0,backend:0,bad:0,bar:[0,6],base:0,based:0,batchmod:1,became:0,been:0,beginning:0,behavior:0,being:0,between:0,big:0,bin:0,bindings:0,bit:0,block:0,blue:0,brazilian:0,brings:0,broken:0,bsd:0,bug:0,bugs:0,build:0,bump:0,bundle:0,bundles:0,but:0,button:0,bytes:0,cache:0,caching:0,called:0,came:0,can:0,cancel:0,cancellable:0,cancellation:0,cancellations:0,cancelled:0,cause:0,caused:0,causing:0,ceiled:0,cells:0,certain:0,change:0,changed:0,changelog:3,changes:0,characters:0,chinese:0,chooses:0,chosen:0,clear:0,clearer:0,click:0,cmd:0,cocoa:0,collection:0,coloring:0,colors:0,column:0,columns:0,com:1,comboboxmodel:0,come:0,command:[0,7],comparison:0,compatibility:0,complement:0,complete:0,configurations:0,confused:0,confusing:0,containing:0,contents:0,context:0,control:7,conversion:0,converted:0,copied:0,copy:0,core:0,correct:0,correctly:0,corrupted:0,couldn:0,count:0,couple:0,crash:0,crashes:0,created:0,creation:0,criteria:0,csv:0,custom:0,czech:0,date:0,debugging:0,dee:0,defaults:0,deleted:0,deletion:[0,7],delta:[0,7],dependencies:0,descriptor:0,designed:0,destination:0,details:0,detection:0,detinov:0,dialog:0,directories:0,directory:0,disable:0,discarded:0,display:0,displayed:0,displaying:0,documentation:0,does:0,don:0,drag:0,dramatically:0,drop:0,dropped:0,due:0,dupe:0,dupeguru:[0,2,4,5,6,7],dupes:0,duplicate:0,duplicates:0,during:0,dutch:0,each:0,edit:0,editions:0,efficient:0,elegantly:0,empty:0,enabled:0,end:0,engine:0,english:1,eric:0,error:0,especially:0,even:0,exact:0,excluded:0,exclusion:0,exe:[4,7],exists:0,exporting:0,expressions:[0,4,7],ext:4,extension:0,fact:0,fairware:[0,1],faq:1,feature:0,features:0,feedback:0,fetching:0,few:0,field:[0,7],figueiredo:0,file:0,filename:0,filenames:0,files:0,filessuperdiffprogsuperdiffprog:4,filter:0,filtered:0,filtering:0,filters:0,find:0,finder:[0,7],fix:0,fixed:0,fixes:0,focus:0,folder:0,folders:0,font:0,foo:6,foobar:4,format:0,found:0,frank:0,freeze:0,french:0,from:0,fuzzy:0,gabriel:0,german:0,get:0,ghosting:0,github:0,glitch:0,glitches:0,going:0,gplv3:0,greatly:0,greek:0,gregor:0,grouping:0,groups:0,gui:0,had:0,handling:0,happening:0,hard:0,hardcoded:0,hardlink:0,hardlinking:[0,4],hardlinks:0,hardness:0,has:[0,7],have:0,having:0,help:0,here:0,homepage:3,hours:0,how:0,hrant:0,html:0,http:[1,7],https:0,icon:0,ignore:0,ignored:0,igor:0,important:0,improve:0,improved:0,improvements:0,inaccuracies:0,inconvenient:0,info:[0,4,7],information:7,initial:0,insensitive:0,instead:0,internal:0,internationalized:0,introduced:0,invocation:0,involved:0,iphoto:[0,2,7],issue:0,issued:0,issues:0,italian:0,item:7,items:0,itunes:[0,2,7],job:0,jumpy:0,just:0,keep:0,keeping:0,keybinding:0,kinds:0,korean:0,koutilellis:0,kyrill:0,large:0,last:0,latin:0,launches:0,launching:0,length:0,libraries:2,license:0,licensed:0,like:0,limitations:0,linux:[0,4,7],lion:0,list:0,little:0,load:0,loading:0,localisation:0,localization:0,localizations:0,localized:0,locations:0,longer:0,longest:0,lose:0,lost:0,lot:0,lots:0,low:0,mac:[0,7],macchampion:1,machines:0,macos:0,made:0,main:0,make:0,making:0,many:0,mark:0,marked:0,marker:0,marking:0,mass:0,match:0,matches:0,maybe:0,mean:0,media:0,memory:0,menu:[0,7],merge:0,message:0,messages:0,might:0,min:0,minimum:0,minor:0,mishandling:0,mistakenly:0,mode:0,more:0,mostly:0,move:[0,7],moved:0,moving:0,mp3:0,much:0,multiple:0,music:0,mydestination:4,nah:0,name:0,names:0,nasty:0,nehyba:0,net:0,non:[0,7],not:[0,7],notes:2,nothing:0,notice:0,now:[0,7],number:0,numeric:0,numerical:[0,7],object:0,obsolete:0,occasional:0,occasionally:0,occurring:0,ohanyan:0,once:0,one:0,only:0,open:0,opening:0,opens:0,operation:0,operations:0,option:0,options:[0,7],order:0,orderable:0,outdated:1,overwrite:0,packaging:0,panel:0,paolo:0,part:0,path:0,paths:0,pavlov:0,permission:0,permissionerror:0,petrashko:0,phan:0,phase:0,picture:0,place:0,places:0,polish:0,popping:0,position:0,possibility:0,post:0,power:0,predictably:0,pref:0,preference:0,preferences:0,present:0,pretty:0,preventing:0,previous:0,prioritization:0,prioritize:0,problem:0,process:0,program:4,progress:0,propagation:0,put:0,pyqt:0,python:0,qestion:1,quicklook:0,quit:0,quitting:0,random:0,reading:0,really:0,recent:0,recycle:0,reduce:0,ref:0,refactorings:0,reference:0,references:0,refers:0,refresh:0,refreshed:0,registration:0,regular:[0,4,7],regular_expressions:7,related:0,release:0,relevant:0,reliability:0,reload:0,reloading:0,remember:0,reminders:0,removable:0,removal:0,remove:0,removed:0,removing:0,rename:0,renamed:0,renaming:0,replace:0,replacing:0,report:0,reporting:0,reports:0,requirement:0,requirements:0,reset:0,responsiveness:0,restored:0,result:0,results:0,revamp:0,reveal:0,rewrite:0,right:0,roman:0,rossi:0,rounded:0,runs:0,russian:0,same:0,save:0,saved:0,saving:0,scan:[0,2],scanned:0,scanner:0,scanning:0,scans:0,screen:0,search:7,section:7,see:1,seeking:0,seldom:0,select:0,selected:0,selecting:0,selection:0,selects:0,send:0,sensible:0,sent:0,separate:0,setting:0,shelve:0,shift:7,shortest:0,show:0,showing:0,sides:0,sierra:0,significantly:0,similar:0,simplified:0,simply:0,since:0,situations:0,size:0,small:0,smartly:0,soft:0,software:0,some:0,somefile:4,somefolder:4,sometimes:0,sort:0,sorting:0,space:7,spanish:0,sparkle:0,speed:0,sphinx:0,stall:0,standard:0,start:0,started:0,starting:0,startup:0,state:0,states:0,status:0,sticky:0,stopped:0,stuck:0,subargument:6,subfolder:4,subfolders:0,subsequent:0,such:0,support:0,sure:0,surrogate:0,switches:0,symlink:0,symlinks:0,sync:0,system:0,systematic:0,table:0,technical:0,tells:0,temporarily:0,text:0,than:0,that:0,the:0,their:0,them:0,then:0,there:0,therefore:0,these:0,threads:0,threshold:0,through:0,tiger:0,too:0,toolbar:7,trash:0,trying:0,tweaked:0,type:0,typos:0,ubuntu:0,ukrainian:0,under:0,unicode:0,unicodeencodeerror:0,universal:0,unmaintained:0,unpaid:0,unsaved:0,update:0,updated:0,updates:0,upgrade:0,upgraded:0,upon:0,usage:0,use_regexp:0,used:0,useful:0,user:0,users:4,using:0,value:0,values:0,various:0,version:[0,1],very:0,victor:0,vietnamese:0,vista:0,visual:0,want:0,warning:[0,7],was:0,wasn:0,way:0,weber:0,weighting:0,well:0,were:0,when:0,where:0,which:0,whole:0,will:0,window:0,windows:[0,7],woes:0,wonder:0,word:0,words:0,work:0,working:0,works:0,would:0,wouldn:0,writable:0,wrong:0,www:[0,7],xhtml:[0,7],yeah:0,you:0,your:0,yuri:0},titles:["Changelog","\u0427\u0430\u0441\u0442\u043e \u0437\u0430\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b","\u0412\u044b\u0431\u043e\u0440 \u043f\u0430\u043f\u043a\u0438","dupeGuru help","\u041f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0435\u043d\u0438\u044f","\u0411\u044b\u0441\u0442\u0440\u044b\u0439 \u0441\u0442\u0430\u0440\u0442","\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0435 \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u043e\u0432 \u0434\u0443\u0431\u043b\u0438\u043a\u0430\u0442\u043e\u0432","\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b"],titleterms:{"\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d":1,"\u0431\u044b\u0441\u0442\u0440":5,"\u0432":1,"\u0432\u043e\u043f\u0440\u043e\u0441":1,"\u0432\u0441\u0435":1,"\u0432\u044b\u0431\u043e\u0440":[2,7],"\u0433\u043e\u0432\u043e\u0440":1,"\u0433\u043e\u0441\u0443\u0434\u0430\u0440\u0441\u0442\u0432":2,"\u0433\u0440\u0443\u043f\u043f":7,"\u0434\u0435\u0439\u0441\u0442\u0432":7,"\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d":1,"\u0434\u0435\u043b\u0430":1,"\u0434\u0435\u043b\u044c\u0442":7,"\u0434\u0435\u043c":1,"\u0434\u043e\u043b\u0436":1,"\u0434\u0440\u0443\u0433":1,"\u0434\u0443\u0431\u043b\u0438\u043a\u0430\u0442":[1,6,7],"\u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430":1,"\u0435\u0433":1,"\u0435\u0441\u0442":1,"\u0437\u0430":1,"\u0437\u0430\u0434\u0430\u0432\u0430":1,"\u0437\u043d\u0430\u043a":1,"\u0437\u043d\u0430\u0447\u0435\u043d":7,"\u0438":7,"\u0438\u0437":1,"\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430":1,"\u043a\u0430\u043a\u043e\u0432":1,"\u043a\u043e\u0440\u0437\u0438\u043d":1,"\u043a\u043e\u0440\u043e\u0431\u043a":1,"\u043a\u043e\u0442\u043e\u0440":1,"\u043b\u0443\u0447\u0448":1,"\u043c\u0430\u0440\u043a\u0438\u0440\u043e\u0432\u043a":7,"\u043c\u0435\u043d":[1,7],"\u043c\u043d\u0435":1,"\u043c\u043e\u0433":1,"\u043c\u043e\u0436\u0435\u0442":1,"\u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a":1,"\u043d\u0435":1,"\u043d\u043e":1,"\u043e":7,"\u043e\u0431\u043c\u0430\u043d\u0443\u0442":7,"\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d":1,"\u043e\u043d":1,"\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d":1,"\u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430":1,"\u043e\u0442\u043a\u043b\u044e\u0447":1,"\u043e\u0442\u043c\u0435\u0442":1,"\u043e\u0442\u043f\u0440\u0430\u0432":1,"\u043f\u0430\u043f\u043a":[1,2],"\u043f\u043b\u0430\u043d":[1,2,7],"\u043f\u043e\u0432\u0442\u043e\u0440\u043d":6,"\u043f\u043e\u043a\u0430\u0437\u0430":7,"\u043f\u043e\u0447":1,"\u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0435\u043d":4,"\u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442":6,"\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440":7,"\u043f\u044b\u0442\u0430":1,"\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442":7,"\u0441\u0432\u043e":1,"\u0441\u0434\u0435\u043b\u0430":1,"\u0441\u043a\u0430\u043d\u0435\u0440":1,"\u0441\u043e\u0441\u0442\u043e\u044f\u043d":1,"\u0441\u0442\u0430\u0440\u0442":5,"\u0441\u0442\u0440\u043e\u043a":1,"\u0442\u0430\u043a":1,"\u0442\u043e\u043b\u044c\u043a":7,"\u0443":1,"\u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d":1,"\u0443\u0434\u0430\u043b":1,"\u0444\u0430\u0439\u043b":1,"\u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446":7,"\u0445\u043e\u0447":1,"\u0447\u0430\u0441\u0442":1,"\u0447\u0435\u043c":1,"\u0447\u0442\u043e":1,"\u0447\u0442\u043e\u0431":1,"\u044d\u0442":1,"\u044f":1,and:3,appname:[],changelog:0,dupeguru:[1,3],help:3,indices:3,tables:3}}) \ No newline at end of file diff --git a/help/uk/.buildinfo b/help/uk/.buildinfo new file mode 100644 index 00000000..a9c3179c --- /dev/null +++ b/help/uk/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: a874776587ce2da814c4810262a52987 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/help/uk/.doctrees/changelog.doctree b/help/uk/.doctrees/changelog.doctree new file mode 100644 index 00000000..98764a4f Binary files /dev/null and b/help/uk/.doctrees/changelog.doctree differ diff --git a/help/uk/.doctrees/environment.pickle b/help/uk/.doctrees/environment.pickle new file mode 100644 index 00000000..7102824a Binary files /dev/null and b/help/uk/.doctrees/environment.pickle differ diff --git a/help/uk/.doctrees/faq.doctree b/help/uk/.doctrees/faq.doctree new file mode 100644 index 00000000..0f375766 Binary files /dev/null and b/help/uk/.doctrees/faq.doctree differ diff --git a/help/uk/.doctrees/folders.doctree b/help/uk/.doctrees/folders.doctree new file mode 100644 index 00000000..fd964587 Binary files /dev/null and b/help/uk/.doctrees/folders.doctree differ diff --git a/help/uk/.doctrees/index.doctree b/help/uk/.doctrees/index.doctree new file mode 100644 index 00000000..019e8d1f Binary files /dev/null and b/help/uk/.doctrees/index.doctree differ diff --git a/help/uk/.doctrees/preferences.doctree b/help/uk/.doctrees/preferences.doctree new file mode 100644 index 00000000..b9a7c491 Binary files /dev/null and b/help/uk/.doctrees/preferences.doctree differ diff --git a/help/uk/.doctrees/quick_start.doctree b/help/uk/.doctrees/quick_start.doctree new file mode 100644 index 00000000..9387bd7d Binary files /dev/null and b/help/uk/.doctrees/quick_start.doctree differ diff --git a/help/uk/.doctrees/reprioritize.doctree b/help/uk/.doctrees/reprioritize.doctree new file mode 100644 index 00000000..e40390d5 Binary files /dev/null and b/help/uk/.doctrees/reprioritize.doctree differ diff --git a/help/uk/.doctrees/results.doctree b/help/uk/.doctrees/results.doctree new file mode 100644 index 00000000..66e941e0 Binary files /dev/null and b/help/uk/.doctrees/results.doctree differ diff --git a/help/uk/_sources/changelog.rst.txt b/help/uk/_sources/changelog.rst.txt new file mode 100644 index 00000000..b1fc6f65 --- /dev/null +++ b/help/uk/_sources/changelog.rst.txt @@ -0,0 +1,705 @@ +:tocdepth: 1 + +Changelog +========= + +**About the word "crash":** When reading this changelog, you might be alarmed at the number of fixes +for "crashes". Be aware that when the word "crash" is used here, it refers to "soft crashes" which +don't cause the application to quit. You simply get an error window that asks you if you want to +send the crash report to Hardcoded Software. Crashes that cause the application to quit are called +"hard crashes" in this changelog. + + +4.0.3 (2016-11-24) +---------------------- + +* Add new picture cache backend: shelve +* Make shelve picture cache backend the active one on MacOS to fix `#394 `__ more + elegantly. [cocoa] +* Remove Sparkle (auto-updates) due to technical limitations. [cocoa] + + +4.0.2 (2016-10-09) +---------------------- + +* Fix systematic crash in Picture Mode under MacOS Sierra. (`#394 `__) +* No change for Linux. Just keeping version in sync. + + +4.0.1 (2016-08-24) +---------------------- + +* Add Greek localization, by Gabriel Koutilellis. (`#382 `__) +* Fix localization base path. [qt] (`#378 `__) +* Fix broken load results dialog. [qt] +* Fix crash on load results. [cocoa] (`#380 `__) +* Save preferences more predictably. [qt] (`#379 `__) +* Fix picture mode's fuzzy block scanner threshold. (`#387 `__) + + +4.0.0 (2016-07-01) +---------------------- + +* Merge Standard, Music and Picture editions in the same application! +* Improve documentation. (`#294 `__) +* Add Polish, Korean, Spanish and Dutch localizations. +* qt: Fix wrong use_regexp option propagation to core. (`#295 `__) +* qt: Fix progress window mistakenly showing up on startup. (`#357 `__) +* Bump Python requirement to v3.4. +* Bump OS X requirement to 10.8 +* Drop Windows support, maybe temporarily. + `Details `__-11-01>`_ +* cocoa: Drop iPhoto, Aperture and iTunes support. Was unmaintained and obsolete. +* Drop "Audio Contents" scan type. Was confusing and seldom useful. +* Change license to GPLv3 + + +3.9.1 (2014-10-17) +---------------------- + +* Fixed ``AttributeError: 'ComboboxModel' object has no attribute 'reset'``. [Linux, Windows] (`#254 `__) +* Fixed ``PermissionError`` on saving results. (`#266 `__) +* Fixed a build problem introduced by Sphinx 1.2.3. +* Updated German localisation, by Frank Weber. + + +3.9.0 (2014-04-19) +---------------------- + +* This is mostly a dependencies upgrade. +* Upgraded to Python 3.3. +* Upgraded to Qt 5. +* Minimum Windows version is now Windows 7 64bit. +* Minimum Ubuntu version is now 14.04. +* Minimum OS X version is now 10.7 (Lion). +* ... But with a couple of little improvements. +* Improved documentation. +* Overwrite subfolders' state when setting states in folder dialog (`#248 `__) +* The error report dialog now brings the user to Github issues. + + +3.8.0 (2013-12-07) +---------------------- + +* Disable symlink/hardlink deletion option when not relevant. (`#247 `__) +* Make Cmd+A select all folders in the Folder Selection dialog. [Mac] (`#228 `__) +* Make non-numeric delta comparison case insensitive. (`#239 `__) +* Fix surrogate-related UnicodeEncodeError on CSV export. (`#210 `__) +* Fixed crash on Dupe Count sorting with Delta + Dupes Only. (`#238 `__) +* Improved documentation. +* Important internal refactorings. +* Dropped Ubuntu 12.04 and 12.10 support. +* Removed the fairware dialog (`More Info `__). + + +3.7.1 (2013-08-19) +---------------------- + +* Fixed folder scan type, which was broken in v3.7.0. + + +3.7.0 (2013-08-17) +---------------------- + +* Improved delta values to support non-numerical values. (`#213 `__) +* Improved the Re-Prioritize dialog's UI. (`#224 `__) +* Added hardlink/symlink support on Windows Vista+. (`#220 `__) +* Dropped 32bit support on Mac OS X. +* Added Vietnamese localization by Phan Anh. + + +3.6.1 (2013-04-28) +---------------------- + +* Improved "Make Selection Reference" to make it clearer. (`#222 `__) +* Improved "Open Selected" to allow opening more than one file at once. (`#142 `__) +* Fixed a few typos here and there. (`#216 `__ `#225 `__) +* Tweaked the fairware dialog (`More Info `__). +* Added Arch Linux packaging +* Added a 64-bit build for Windows. +* Improved Russian localization by Kyrill Detinov. +* Improved Brazilian localization by Victor Figueiredo. + + +3.6.0 (2012-08-08) +---------------------- + +* Added "Export to CSV". (`#189 `__) +* Added "Replace with symlinks" to complement "Replace with hardlinks". [Mac, Linux] (`#194 `__) +* dupeGuru now tells how many duplicates were affected after each re-prioritization operation. (`#204 `__) +* Added Longest/Shortest filename criteria in the re-prioritize dialog. (`#198 `__) +* Fixed result table cells which mistakenly became writable in v3.5.0. [Mac] (`#203 `__) +* Fixed "Rename Selected" which was broken since v3.5.0. [Mac] (`#202 `__) +* Fixed a bug where "Reset to Defaults" in the Columns menu wouldn't refresh menu items' marked state. +* Added Brazilian localization by Victor Figueiredo. + + +3.5.0 (2012-06-01) +---------------------- + +* Added a Deletion Options panel. +* Greatly improved memory usage for big scans. +* Added a keybinding for the filter field. (`#182 `__) [Mac] +* Upgraded minimum requirements for Ubuntu to 12.04. + + +3.4.1 (2012-04-14) +---------------------- + +* Fixed the "Folders" scan type. [Mac] +* Fixed localization issues. [Windows, Linux] + + +3.4.0 (2012-03-29) +---------------------- + +* Improved results window UI. [Windows, Linux] +* Added a dialog to edit the Ignore List. +* Added the ability to sort results by "marked" status. +* Fixed "Open with default application". (`#190 `__) +* Fixed a bug where there would be a false reporting of discarded matches. (`#195 `__) +* Fixed various localization glitches. +* Fixed hard crashes on crash reporting. (`#196 `__) +* Fixed bug where the details panel would show up at inconvenient places in the screen. [Windows, Linux] + + +3.3.3 (2012-02-01) +---------------------- + +* Fixed crash on adding some folders. [Mac OS X] +* Added Ukrainian localization by Yuri Petrashko. + + +3.3.2 (2012-01-16) +---------------------- + +* Fixed random hard crashes (yeah, again). [Mac OS X] +* Fixed crash on Export to HTML. [Windows, Linux] +* Added Armenian localization by Hrant Ohanyan. +* Added Russian localization by Igor Pavlov. + + +3.3.1 (2011-12-02) +---------------------- + +* Fixed a couple of nasty crashes. + + +3.3.0 (2011-11-30) +---------------------- + +* Added multiple-selection in folder selection dialog for a more efficient folder removal. (`#179 `__) +* Fixed a crash in the prioritize dialog. (`#178 `__) +* Fixed a bug where mass marking with a filter would mark more than filtered duplicates. (`#181 `__) +* Fixed random hard crashes. [Mac OS X] (`#183 `__ `#184 `__) +* Added Czech localization by Aleš Nehyba. +* Added Italian localization by Paolo Rossi. + + +3.2.1 (2011-10-02) +---------------------- + +* Fixed a couple of broken action bindings from v3.2.0. + + +3.2.0 (2011-09-27) +---------------------- + +* Added duplicate re-prioritization dialog. (`#138 `__) +* Added font size preference for duplicate table. (`#82 `__) +* Added Quicklook support. [Mac OS X] (`#21 `__) +* Improved behavior of Mark Selected. (`#139 `__) +* Improved filename sorting. (`#169 `__) +* Added Chinese (Simplified) localization by Eric Dee. +* Tweaked the fairware system. +* Upgraded minimum requirements to OS X 10.6 and Ubuntu 11.04. + + +3.1.2 (2011-08-25) +---------------------- + +* Fixed a bug preventing the Folders scan from working. (`#172 `__) + + +3.1.1 (2011-08-24) +---------------------- + +* Added German localization by Gregor Tätzner. +* Improved OS X Lion compatibility. [Mac OS X] +* Made the file collection phase cancellable. (`#168 `__) +* Fixed glitch in folder window upon selecting a folder state. [Windows, Linux] (`#165 `__) +* Fixed a text coloring glitch in the results. (`#156 `__) +* Fixed glitch in the sorting feature of the Folder column. (`#161 `__) +* Make sure that saved results have the ".dupeguru" extension. [Linux] (`#157 `__) + + +3.1.0 (2011-04-16) +---------------------- + +* Added the "Folders" scan type. (`#89 `__) +* Fixed a couple of crashes. (`#140 `__ `#149 `__) + + +3.0.2 (2011-03-16) +---------------------- + +* Fixed crash after removing marked dupes. (`#140 `__) +* Fixed crash on error handling. [Windows] (`#144 `__) +* Fixed crash on copy/move. [Windows] (`#148 `__) +* Fixed crash when launching dupeGuru from a very long folder name. [Mac OS X] (`#119 `__) +* Fixed a refresh bug in directory panel. (`#153 `__) +* Improved reliability of the "Send to Trash" operation. [Linux] +* Tweaked Fairware reminders. + + +3.0.1 (2011-01-27) +---------------------- + +* Restored the context menu which had been broken in 3.0.0. [Mac OS X] (`#133 `__) +* Fixed a bug where an "unsaved results" warning would be issued on quit even with empty results. (`#134 `__) +* Removed focus from the cancel button in the progress dialog to avoid accidental cancellations. [Mac OS X] (`#135 `__) +* Folders added through drag and drop are added to the recent folders list. (`#136 `__) +* Added a debugging mode. (`#132 `__) +* Fixed french localization glitches. + + +3.0.0 (2011-01-24) +---------------------- + +* Re-designed the UI. (`#129 `__) +* Internationalized dupeGuru and localized it to french. (`#32 `__) +* Changed the format of the help file. (`#130 `__) + + +2.12.3 (2011-01-01) +---------------------- + +* Fixed bug causing results to be corrupted after a scan cancellation. (`#120 `__) +* Fixed crash when fetching Fairware unpaid hours. (`#121 `__) +* Fixed crash when replacing files with hardlinks. (`#122 `__) + + +2.12.2 (2010-10-05) +---------------------- + +* Fixed delta column colors which were broken since 2.12.0. +* Fixed column sorting crash. (`#108 `__) +* Fixed occasional crash during scan. (`#106 `__) + + +2.12.1 (2010-09-30) +---------------------- + +* Re-licensed dupeGuru to BSD and made it `Fairware `__. + + +2.12.0 (2010-09-26) +---------------------- + +* Improved UI with a little revamp. +* Added the possibility to place hardlinks to references after having deleted duplicates. [Mac OS X, Linux] (`#91 `__) +* Added an option to ignore duplicates hardlinking to the same file. [Mac OS X, Linux] (`#92 `__) +* Added multiple selection in the "Add Directory" dialog. [Mac OS X] (`#105 `__) +* Fixed a bug preventing drag & drop from working in the Directories panel. [Windows, Linux] + + +2.11.1 (2010-08-26) +---------------------- + +* Fixed HTML exporting which was broken in 2.11.0. + + +2.11.0 (2010-08-18) +---------------------- + +* Added the ability to save results (and reload them) at arbitrary locations. +* Improved the way reference files in dupe groups are chosen. (`#15 `__) +* Remember size/position of all windows between launches. (`#102 `__) +* Fixed a bug sometimes preventing dupeGuru from reloading previous results. +* Fixed a bug sometimes causing the progress dialog to be stuck there. [Mac OS X] (`#103 `__) +* Removed the Creation Date column, which wasn't displaying the correct value anyway. (`#101 `__) + + +2.10.1 (2010-07-15) +---------------------- + +* Fixed a couple of crashes. (`#95 `__, `#97 `__, `#100 `__) + + +2.10.0 (2010-04-13) +---------------------- + +* Improved error messages when files can't be sent to trash, moved or copied. +* Added a custom command invocation action. (`#12 `__) +* Filters are now applied on whole paths. (`#4 `__) + + +2.9.2 (2010-02-10) +---------------------- + +* dupeGuru is now 64-bit on Mac OS X! +* Fixed a crash upon quitting when support folder is not present. (`#83 `__) +* Fixed a crash during sorting. (`#85 `__) +* Fixed selection glitches, especially while renaming. (`#93 `__) + + +2.9.1 (2010-01-13) +---------------------- + +* Improved memory usage for Contents scans. (`#75 `__) +* Improved scanning speed when ref directories are involved. (`#77 `__) +* Show a message dialog at the end of the scan if no duplicates are found. (`#81 `__) +* Fixed a bug sometimes causing the small files threshold pref to be ignored. [Mac OS X] (`#75 `__) + + +2.9.0 (2009-11-03) +---------------------- + +* Significantly improved speed and memory usage of big contents-based scans. +* Added drag & drop support in the Directories panel. (`#9 `__) +* Fixed a bug causing dupeGuru to be confused if a scanned file was moved during the scan. (`#72 `__) +* Dropped support for Mac OS X 10.4 (Tiger) + + +2.8.2 (2009-10-14) +---------------------- + +* Improved directory selection in the Directories panel (Windows). (`#56 `__) +* Fixed a bug preventing dupeGuru from starting on certain machines (Windows). (`#68 `__) +* Fixed a crash during very big scans. (`#70 `__) + + +2.8.1 (2009-10-02) +---------------------- + +* Fixed crash with filtering when regular expressions were enabled. (`#60 `__) +* Fixed crash when setting directories' state. (Mac OS X) (`#66 `__) +* Fixed crash with Make Reference when certain filters are applied. (Mac OS X) (`#55 `__) +* Improved error handling during delete/move/copy actions. (`#62 `__ `#65 `__) + + +2.8.0 (2009-09-07) +---------------------- + +* Added support for all kinds of bundle (not just applications) (Mac OS X) (`#11 `__) +* Re-introduced the Export to XHTML feature to Windows. (`#14 `__) +* Improved Export to XHTML speed. (`#14 `__) +* Improved Contents scanning speed for large files. (`#33 `__) +* Improved the grouping algorithm to reduce the number of discarded files in non-exact scans. (`#51 `__) +* Stopped showing the same file on the 2 sides of the details panel when a ref file is selected. (`#50 `__) +* Fixed crashes in the Directories panel. (`#46 `__) + + +2.7.3 (2009-06-20) +---------------------- + +* Fixed bugs with selection being jumpy during "Make Reference" actions and Power Marker + switches. (`#3 `__) +* Fixed crash happening when a file with non-roman characters couldn't be analyzed. (`#30 `__) +* Fixed crash sometimes happening during the file collection phase in scanning. (`#38 `__) +* Restored double-click and right-click behavior lost in the PyQt move (Windows). (`#34 `__ `#35 `__) + + +2.7.2 (2009-06-10) +---------------------- + +* Fixed an occasional crash on Copy/Move operations. (`#16 `__) +* Added automatic exclusion for sensible folders (like system folders). (`#20 `__) +* Fixed an occasional crash when application files were part of the results (Mac OS X). (`#25 `__) + + +2.7.1 (2009-05-29) +---------------------- + +* Fixed a bug causing crashes when having application files in the results. +* Fixed a bug causing a GUI freeze at the beginning of a scan with a lot of files. +* Fixed a bug that sometimes caused a crash when an action was cancelled, and then started again. + + +2.7.0 (2009-05-25) +---------------------- + +* Converted the Windows GUI to Qt. +* Improved the reliability of the scanning process. + + +2.6.1 (2009-03-27) +---------------------- + +* **Fixed** an occasional crash caused by permission issues. +* **Fixed** a bug where the "X discarded" notice would show a too large number of discarded + duplicates. + + +2.6.0 (2008-09-10) +---------------------- + +* **Added** a small file threshold preference. +* **Added** a notice in the status bar when matches were discarded during the scan. +* **Improved** duplicate prioritization (smartly chooses which file you will keep). +* **Improved** scan progress feedback. +* **Improved** responsiveness of the user interface for certain actions. + + +2.5.4 (2008-08-10) +---------------------- + +* **Improved** the speed of results loading and saving. +* **Fixed** a crash sometimes occurring during duplicate deletion. + + +2.5.3 (2008-07-08) +---------------------- + +* **Improved** unicode handling for filenames. dupeGuru will now find a lot more duplicates if your files have non-ascii characters in it. +* **Fixed** "Clear Ignore List" crash in Windows. + + +2.5.2 (2008-01-10) +---------------------- + +* **Improved** the handling of low memory situations. +* **Improved** the directory panel. The "Remove" button changes to "Put Back" when an excluded directory is selected. +* **Improved** scan, delete and move speed in situations where there were a lot of duplicates. +* **Fixed** occasional crashes when moving bundles (such as .app files). +* **Fixed** occasional crashes when moving a lot of files at once. + + +2.5.1 (2007-11-22) +---------------------- + +* **Added** the "Remove empty folders" option. +* **Fixed** results load/save issues. +* **Fixed** occasional status bar inaccuracies when the results are filtered. + + +2.5.0 (2007-09-15) +---------------------- + +* **Added** post scan filtering. +* **Fixed** issues with the rename feature under Windows +* **Fixed** some user interface annoyances under Windows + + +2.4.8 (2007-04-14) +---------------------- + +* **Improved** UI responsiveness (using threads) under Mac OS X. +* **Improved** result load/save speed and memory usage. + + +2.4.7 (2007-03-10) +---------------------- + +* **Fixed** a "bad file descriptor" error occasionally popping up. +* **Fixed** a bug with non-latin directory names. + + +2.4.6 (2007-02-10) +---------------------- + +* **Added** Re-orderable columns. In fact, I re-added the feature which was lost in the C# conversion in 2.4.0 (Windows). +* **Changed** the behavior of the scanning engine when setting the hardness to 100. It will now only match files that have their words in the same order. +* **Fixed** a bug with all the Delete/Move/Copy actions with certain kinds of files. + + +2.4.5 (2007-01-11) +---------------------- + +* **Fixed** a bug with the Move action. + + +2.4.4 (2007-01-07) +---------------------- + +* **Fixed** a "ghosting" bug. Dupes deleted by dupeGuru would sometimes come back in subsequent scans (Windows). +* **Fixed** bugs sometimes making dupeGuru crash when marking a dupe (Windows). +* **Fixed** some minor visual glitches (Windows). + + +2.4.3 (2006-12-08) +---------------------- + +* **Fixed** a mishandling of ".app" files (OS X). +* **Fixed** a bug preventing files from "reference" directories to be displayed in blue in the results (Windows). +* **Fixed** a bug preventing some files to be sent to the recycle bin (Windows). +* **Fixed** a bug in the packaging preventing certain Windows configurations to start dupeGuru at all. + + +2.4.2 (2006-11-18) +---------------------- + +* **Fixed** a bug with directory states. + + +2.4.1 (2006-11-15) +---------------------- + +* **Fixed** a bug causing the ignore list not to be saved. +* **Fixed** a bug sometimes making delete and move operations stall. + + +2.4.0 (2006-11-10) +---------------------- + +* **Changed** the Windows interface. It is now .NET based. +* **Added** an auto-update feature to the windows version. +* **Changed** the way power marking works. It is now a mode instead of a separate window. +* **Changed** the "Size (MB)" column for a "Size (KB)" column. The values are now "ceiled" instead of rounded. Therefore, a size "0" is now really 0 bytes, not just a value too small to be rounded up. It is also the case for delta values. +* **Removed** the min word length/count options. These came from Mp3 Filter, and just aren't used anymore. Word weighting does pretty much the same job. + + +2.3.4 (2006-11-07) +---------------------- + +* **Improved** speed and memory usage of the scanning engine, again. Does it mean there was a lot of improvements to be made? Nah... + + +2.3.3 (2006-11-02) +---------------------- + +* **Improved** speed and memory usage of the scanning engine, especially when the scan results in a lot of duplicates. +* Now I wonder if Sparkle is going to work well... + + +2.3.2 (2006-10-16) +---------------------- + +* **Added** an auto-update feature in the Mac OS X version (with Sparkle). +* **Fixed** a bug preventing some duplicate reports to be created correctly under Windows. + + +2.3.1 (2006-10-02) +---------------------- + +* **Fixed** a bug preventing some duplicates to be found, especially when scanning lots of files. + + +2.3.0 (2006-09-22) +---------------------- + +* **Added** XHTML export feature. + + +2.2.10 (2006-08-31) +---------------------- + +* **Added** sticky columns. +* **Fixed** an issue with file caching between scans. +* **Fixed** an issue preventing some duplicates from being deleted/moved/copied. + + +2.2.9 (2006-08-27) +---------------------- + +* **Fixed** an issue with ignore list and unicode. +* **Fixed** an issue with file attribute fetching sometimes causing dupeGuru to crash. +* **Fixed** an issue in the directories panel under Windows. + + +2.2.8 (2006-08-17) +---------------------- + +* **Fixed** an issue in the duplicate seeking engine preventing some duplicates to be found. + + +2.2.7 (2006-08-12) +---------------------- + +* **Improved** unicode support. +* **Improved** the "Reveal in Finder" ("Open Containing Folder" in Windows) feature so it selects the file in the folder it opens. + + +2.2.6 (2006-08-07) +---------------------- + +* **Improved** the ignore list system. +* dupeGuru is now a Universal application on Mac OS X. + + +2.2.5 (2006-07-26) +---------------------- + +* **Improved** application (.app) dupe detection on Mac OS X. +* **Fixed** an issue that occasionally made dupeGuru crash on startup. + + +2.2.4 (2006-06-27) +---------------------- + +* **Fixed** an issue with Move and Copy features. + + +2.2.3 (2006-06-15) +---------------------- + +* **Improved** duplicate scanning speed. +* **Added** a warning that a file couldn't be renamed if a file with the same name already exists. + + +2.2.2 (2006-06-07) +---------------------- + +* **Added** "Rename Selected" feature. +* **Fixed** some minor issues with "Reload Last Results" feature. +* **Fixed** ignore list issues. + + +2.2.1 (2006-05-22) +---------------------- + +* **Fixed** occasional progress bar woes under Windows. +* **Fixed** a bug in the registration system under Windows. +* Nothing has been changed in the Mac OS X version, but I want to keep version in sync. + + +2.2.0 (2006-05-10) +---------------------- + +* **Added** destination path re-creation options. +* **Added** an ignore list. +* **Changed** the main icon. +* **Improved** dramatically the delta values feature. + + +2.1.2 (2006-04-18) +---------------------- + +* **Added** the "Match similar words" option. +* **Fixed** Power marking issues under Mac. + + +2.1.1 (2006-04-14) +---------------------- + +* **Added** the "Display delta values" option. +* **Improved** Power marking sorting speed under Mac. +* **Fixed** Power marking sorting issues. + + +2.1.0 (2006-04-03) +---------------------- + +* **Added** the Power Marker feature. +* **Fixed** a column sorting bug. The results would sometimes lose their sort order. +* **Fixed** a bug with the Make Reference feature. The results sometimes wasn't correctly refreshed after the reference switch. + + +2.0.1 (2006-03-23) +---------------------- + +* **Fixed** an issue occasionally occurring when trying to reload results from removable media that is no longer present. + + +2.0.0 (2006-03-17) +---------------------- + +* Complete rewrite. +* Now runs on Mac OS X. + + +1.0.0 (2004-09-24) +---------------------- + +* Initial release. + diff --git a/help/uk/_sources/faq.rst.txt b/help/uk/_sources/faq.rst.txt new file mode 100644 index 00000000..cf685d5f --- /dev/null +++ b/help/uk/_sources/faq.rst.txt @@ -0,0 +1,117 @@ +Часті питання +========================== + +.. topic:: Що таке dupeGuru? + + .. only:: edition_se + + dupeGuru це інструмент для пошуку дублікатів файлів на вашому комп'ютері. Він може сканувати або імен файлів або контенту. Файл функцій сканування нечіткого відповідності алгоритму, який дозволяє знайти однакові імена файлів, навіть якщо вони не зовсім те ж саме. + + .. only:: edition_me + + dupeGuru Music Edition являє собою інструмент для пошуку дубльованих пісень у вашій музичній колекції. Він може будувати свою сканування файлів, тегам або змісту. Файл і тег перевіряє функція нечіткого відповідності алгоритм, який може знаходити дублікати файлів або теги, навіть якщо вони не зовсім те ж саме. + + .. only:: edition_pe + + dupeGuru Picture Edition (PE для стислості) являє собою інструмент для пошуку дублікатів фотографій на вашому комп'ютері. Не тільки він може знайти точні відповідності, але він також може знайти дублікати серед фотографій різного роду (PNG, JPG, GIF і т.д..) І якість. + +.. topic:: Що робить його краще, ніж інші сканери дублювати? + + Сканування є надзвичайно гнучкою. Ви можете налаштувати його, щоб дійсно отримати, яких результатів ви хочете. Ви можете прочитати більше про опція налаштування dupeGuru в :doc:`Установки `. + +.. topic:: Наскільки безпечно використовувати dupeGuru? + + Дуже безпечною. dupeGuru був розроблений, щоб переконатися, що ви не видаляєте файли, які ви не хотіли видалити. По-перше, існує система відліку папку, яка дозволяє визначити папки, в яких ви абсолютно не ** ** хочете dupeGuru, щоб ви видаляєте файли там, і тоді є система контрольної групи, що гарантує, що ви завжди ** * * тримати принаймні один член групи дублікатів. + +.. topic:: Які обмеження демо dupeGuru? + + У демо-режимі, ви можете тільки виконувати дії над 10 дублікати відразу. В + `Fairware `_ mode, однак, Є ніяких обмежень. + +.. topic:: Знак коробку файл я хочу видалити відключена. Що я повинен зробити? + + Ви не можете помітити посилання (перший файл) дублікат групи. Однак те, що ви можете зробити, полягає в сприянні дублювати файл довідки. Таким чином, якщо файл, який Ви хочете, щоб відзначити цю посилання, виділіть дублікатів файлів в групу, яку ви хочете просувати на посилання, і натисніть на кнопку **Дії -> Додати вибраної посилання**. Якщо посилання файл з папки посилання (назва файлу написані на синіми літерами), ви не можете видалити його з вихідного положення. + +.. topic:: У мене є папка, з якої я справді не хочу, щоб видалити файли. + + Якщо ви хочете бути впевнені, що dupeGuru ніколи не буде видаляти файл з певної папки, переконайтеся, що встановили в стан **Посилання на:** документ: :doc:`folders`. + +.. topic:: Що це за '(X відкидається) "повідомлення в рядку стану? + + У деяких випадках, кілька матчів не включені в остаточні результати з міркувань безпеки. Дозвольте мені навести приклад. У нас є 3 файли: A, B і C. Ми скануємо їх за допомогою фільтра низьких твердості. Сканер визначає, що матчі з B, матчі з С, але робить B ** не ** матч з С. При цьому, dupeGuru має вигляд проблеми. Вона не може створити дублікат групи А, В і С в це, тому що не всі файли в групі буде відповідати разом. Це може створити 2 групи: одна група AB, а потім одна група AC, але це не буде, з міркувань безпеки. Давайте думати про це: якщо Б не співпадає з С, вона, ймовірно, означає, що або B, C або обидва на самому ділі не дублікати. Якщо не було б 2 групи (АВ і АС), ви б у кінцевому підсумку видалити обидва B і C. І якщо один з них не дублювати, що насправді не те, що ви хочете робити, правильно? Так що dupeGuru робить у такому випадку є, щоб відмінити матч AC (і додає повідомлення в рядку стану). Таким чином, якщо ви вилучили B і повторно запустити сканування, вам доведеться відповідати змінного струму в наступний результат. + +.. topic:: Я хочу, щоб відзначити всі файли з визначеної папки. Що я можу зробити? + + Включити :doc:`ошукані Тільки ` режим і натиснути на папку колонки для сортування дублікатів по папках. Потім він буде легким для вас, щоб вибрати всі дублікати з тієї ж папці, а потім натиснути клавішу пробіл, щоб відзначити всі вибрані дублікатів. + +.. only:: edition_se or edition_pe + + .. topic:: Я хочу, щоб видалити всі файли, які більше 300 Кб від їх посиланням на файл. Що я можу зробити? + + * Включити :doc:`ошукані Тільки ` режимі. + * Включити **Значення Delta** режимі. + * Натисніть на "Розмір" стовпця для сортування результатів за розміром. + * Вибрати всі дублікати нижче -300. + * Натисніть на **Видалити вибрані з результатів**. + * Вибрати всі дублікати більше 300 осіб. + * Натисніть на **Видалити вибрані з результатів**. + + .. topic:: Я хочу, щоб мої останні змінені файли файли довідки. Що я можу зробити? + + * Включити :doc:`ошукані Тільки ` режимі. + * Включити **Значення Delta** режимі. + * Натисніть на "Модифікація" колонку для сортування результатів за датою зміни. + * Натисніть на "Модифікація" колона знову змінити порядок сортування. + * Вибрати всі дублікати за 0. + * Натисніть на **Зробити вибраної посилання**. + + .. topic:: Я хочу, щоб відзначити все дублікати, що містять слово "копія". Як мені це зробити? + + * **Windows**: Натисніть на **Дії -> Застосувати фільтр**, потім введіть "копія", натисніть кнопку ОК. + * **Mac OS X**: Типу "копія" в "Фільтр" поле на панелі інструментів. + * Натисніть на Марка **-> Позначити всі**. + +.. only:: edition_me + + .. topic:: Я хочу, щоб видалити всі пісні, які більш ніж на 3 секунди від своєї посиланням на файл. Що я можу зробити? + + * Включити :doc:`ошукані Тільки ` режимі. + * Включити **Значення Delta** режимі. + * Натисніть на "Час" колонку для сортування результатів за часом. + * Вибрати всі дублікати нижче -00:03. + * Натисніть на **Видалити вибрані з результатів**. + * Вибрати всі дублікати за 00:03. + * Натисніть на **Видалити вибрані з результатів**. + + .. topic:: Я хочу, щоб мій високий бітрейт файлів пісні посилання. Що я можу зробити? + + * Включити :doc:`ошукані Тільки ` режимі. + * Включити **Значення Delta** режимі. + * Натисніть на "Бітрейт" колонку для сортування результатів по бітрейт. + * Натисніть на "Бітрейт" колона знову змінити порядок сортування. + * Вибрати всі дублікати за 0. + * Натисніть на **Зробити вибраної посилання**. + + .. topic:: Я не хочу [жити] і [ремікс] версії моїх пісень вважатися дублікатами. Як мені це зробити? + + Якщо ваше порівняння поріг досить низьким, ви, ймовірно, в кінцевому підсумку з живою і ремікс версії ваших пісень у своїх результатах. Там ви нічого не можете зробити, щоб запобігти цьому, але є дещо можна зробити, щоб легко видалити їх зі свого результати після сканування: після сканування, фільтрації. Якщо, наприклад, ви хочете видалити всі пісні з чим-небудь у квадратних дужках []: + + * **Windows**: Натисніть на **Дії -> Застосувати фільтр**, а потім введіть "[*]", натисніть кнопку ОК. + * **Mac OS X**: Тип "[*]" в "Фільтр" поле на панелі інструментів. + * Натисніть на Марка **-> Позначити всі**. + * Натисніть на **Дії -> Видалити вибрані з результатів**. + +.. topic:: Я намагався відправити свої дублікати в корзину, але dupeGuru говорить мені, він не може це зробити. Чому? Що я можу зробити? + + Більшу частину часу, тому dupeGuru не можете відправляти файли до кошика через права доступу до файлів. Ви повинні * написати * дозволу на файли, які ви хочете відправити у кошик. Якщо ви не знайомі з командним рядком, ви можете використовувати утиліти, такі як `BatChmod `_ виправити Ваші права. + + Якщо dupeGuru ще дає вам неприємності після фіксації ваших прав, було кілька випадків, коли за допомогою "Переміщення Позначено до ..." як обхідного шляху зробили свою справу. Таким чином, замість відправки файлів в корзину, ви посилаєте їх в тимчасову папку з "Переміщати Позначено до ..." дії, а потім видалити цю тимчасову папку вручну. + + .. only:: edition_pe + + Якщо ви намагаєтеся видалити *iPhoto*, то причина збою інша. Видалення не виконується, так dupeGuru не може спілкуватися з iPhoto. Врахуйте, що для видалення коректної роботи, ви не повинні грати навколо iPhoto в той час як dupeGuru працює. Крім того, іноді, система Applescript, здається, не знають, де знайти Iphoto запустити його. Це може допомогти в таких випадках для запуску Iphoto * до * ви посилаєте дублікатів в корзину. + + Якщо все це не так, `контакт УГ підтримки `_, ми зрозуміти це. + +.. todo:: This FAQ qestion is outdated, see english version. + diff --git a/help/uk/_sources/folders.rst.txt b/help/uk/_sources/folders.rst.txt new file mode 100644 index 00000000..21f1a09c --- /dev/null +++ b/help/uk/_sources/folders.rst.txt @@ -0,0 +1,23 @@ +Вибір папки +================ + +Перше вікно, ви бачите, коли ви запускаєте dupeGuru це вікно вибору папки. Це вікно містить список папок, які будуть скануватися при натисканні на **Сканування**.Це вікно досить проста у використанні. Якщо ви хочете додати папку, натисніть на кнопку **+**. Якщо ви додали папки перш, спливаюче меню зі списком останніх папки додав з'явиться. Ви можете натиснути на одну з них, щоб додати його прямо в свій список. Якщо натиснути на перший пункт меню, **Додати новий папку ...**, вам буде запропоновано ввести папку додати. Якщо ви ніколи не додається папка, не з'явиться меню, і ви будете безпосередньо буде запропоновано ввести нову папку додати. + +Альтернативний спосіб для додавання папок в список, щоб перетягнути їх в списку. + +Щоб видалити папку, виберіть папку, видалити, і натисніть на **-**. Якщо папці вибирається при натисканні кнопки, обраної папки буде встановлений в **виключені** стану (див. нижче), а не видалений. + +Папка держав +------------- + +Кожна папка може знаходитися в одному з цих 3-х держав: + +* ** Нормальний: ** дублікати знайдені в цю папку можна видалити. +* ** Довідка: ** Дублікати знайти в цій папці **не може** бути видалені. Файли з цієї папки можна тільки в кінцевому підсумку в **посилання** позиція в групі обдурити. Якщо більш ніж один файл з папки посилання в кінцевому підсумку в тій же групі обдурити, тільки один, будуть збережені. Інші будуть видалені з групи. +* ** Не включено: ** Файли в цьому каталозі не буде включений у перевірку. + +Стан за замовчуванням до папки, звичайно, **Нормальний**. Ви можете використовувати **Посилання** стан для папки, якщо ви хочете бути впевнені, що ви не будете видаляти будь-які файли з нього. + +Коли ви встановлюєте стан каталог, все підпапки цієї папки автоматично успадковує цей стан, якщо явно не включений стан підпапку в. + +.. todo:: Add iPhoto/Aperture/iTunes libraries notes diff --git a/help/uk/_sources/index.rst.txt b/help/uk/_sources/index.rst.txt new file mode 100644 index 00000000..19511fce --- /dev/null +++ b/help/uk/_sources/index.rst.txt @@ -0,0 +1,47 @@ +dupeGuru help +=============== + +.. only:: edition_se + + Цей документ також доступна на `французькому `__, `німецький `__ і `Вірменський `__. + +.. only:: edition_me + + Цей документ також доступна на `французькому `__, `німецький `__ і `Вірменський `__. + +.. only:: edition_pe + + Цей документ також доступна на `французькому `__, `німецький `__ і `Вірменський `__. + +.. only:: edition_se or edition_me + + dupeGuru це інструмент для пошуку дублікатів файлів на вашому комп'ютері. Він може сканувати або імен файлів або вмісту. Файл функцій сканування нечіткого відповідності алгоритму, який дозволяє знайти однакові імена файлів, навіть якщо вони не зовсім те ж саме. + +.. only:: edition_pe + + dupeGuru Picture Edition (PE для стислості) являє собою інструмент для пошуку дублікатів фотографій на вашому комп'ютері. Не тільки він може знайти точні відповідності, але він також може знайти дублікати серед фотографій різного роду (PNG, JPG, GIF і т.д..) І якість. + +Хоча dupeGuru може бути легко використана без документації, читання цього файлу допоможе вам освоїти його. Якщо ви шукаєте керівництво для вашої першої дублювати сканування, ви можете поглянути на: :doc:`Quick Start ` + +Це гарна ідея, щоб зберегти dupeGuru оновлено. Ви можете завантажити останню версію на своєму `homepage`_. + +Contents: + +.. toctree:: + :maxdepth: 2 + + quick_start + folders + preferences + results + reprioritize + faq + changelog + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` + +.. _homepage: https://www.hardcoded.net/dupeguru diff --git a/help/uk/_sources/preferences.rst.txt b/help/uk/_sources/preferences.rst.txt new file mode 100644 index 00000000..6489f418 --- /dev/null +++ b/help/uk/_sources/preferences.rst.txt @@ -0,0 +1,64 @@ +Уподобання +=========== + +.. only:: edition_se + + **Тип сканування:** Цей параметр визначає, який аспект файли будуть порівнюватися в дублікат сканування. Якщо вибрати **Файл** , dupeGuru будемо порівнювати кожне імена файлів слово за слово, і, залежно від інших параметрів нижче, він буде визначати, чи достатньо слів відповідність розглянути 2 файлів дублікатів. Якщо вибрати **Вміст**, тільки файли з точно такою ж контент буде матч. + + **Папки** типу сканування трохи особливим. Коли ви обираєте його, dupeGuru проведе пошук дублікатів *папки* замість того, щоб дублікатів файлів. Для визначення того, дві папки, дублюють один одного, всі файли, що містяться в папках будуть перевірятися, і якщо вміст **всі** файли в матчі папки, папки будуть вважатися дублікатами. + + **Фільтра Твердість:** Якщо ви вибрали **Папки** Файл типу сканування, ця опція визначає, як схожі два імені повинно бути для dupeGuru розглядати їх дублікатів. Якщо фільтр твердості, наприклад 80, то це означає, що 80% слів з ​​двох імен файлів повинні збігатися. Для визначення відповідності відсоток, dupeGuru перший підраховує загальну кількість слів в **обох** файлу, то підрахувати кількість слів відповідності (кожне слово відповідності вважаються 2), а потім розділіть кількість слів відповідності на загальне число слів. Якщо результат більше або дорівнює фільтр твердість, у нас є дублікати матчу. Наприклад, "ABCD" і "CDE" мають відповідний відсоток 57 (4 слова відповідності, 7 всього слів). + +.. only:: edition_me + + **Тип сканування:** Цей параметр визначає, який аспект файли будуть порівнюватися в дублікат сканування. Характер дублювати сканування варіюється в залежності від того, що ви обираєте для цієї опції. + + * **Файл:** Кожна пісня буде мати свій файл розбитий на слова, а потім кожне слово буде в порівнянні з обчислити відповідні відсотки. Якщо цей відсоток вище або дорівнює **жорсткість фільтра** (див. нижче детальніше), dupeGuru розгляне 2 пісні дублікатів. + * **Файл - Поля:** Як **Файл** , за винятком того, що як тільки ім'я файлу були розділені на слова, ці слова потім групуються в поля. Роздільник полів "-". Остаточний відсоток відповідності буде найнижчим відповідний відсоток серед полів. Таким чином, "Виконавець - Назва" і "Артист - Інші Назва" матиме відповідний відсоток 50 (С **Файл** сканування, це буде 75). + * **Файл - Поля (нема наказу):** Як **Супер - Поля**, крім того, що порядок полів не має значення. Наприклад, "Виконавець - Назва" і "Назва - Артист" матиме відповідний відсоток з 100 замість 0. + * **Теги:** Цей метод прочитує мітки (метадані) кожної пісні й порівняти їх полям. Цей метод, як **Супер - Поля**, вважає низький відповідне поле в якості остаточного відповідний відсоток. + * **Склад:** Цей метод сканування використовувати фактичний зміст пісні, щоб визначити, які є дублікатами. За 2 пісні у відповідності з цим методом, вони повинні мати **такий самий змісту**. + * **Аудіо контенту:** Те ж зміст, але тільки в аудіо-контент порівнюється (без метаданих). + + **Фільтра Твердість:** Якщо ви вибрали ім'я файлу або тегами типу сканування, ця опція визначає, як схожі два імені / теги повинні бути для dupeGuru розглядати їх дублікатів. Якщо фільтр твердості, наприклад 80, то це означає, що 80% слів з двох імен файлів повинні збігатися. Для визначення відповідності відсоток, dupeGuru перший підраховує загальну кількість слів в **обох** файлу, то підрахувати кількість слів відповідності (кожне слово відповідності вважаються 2), а потім розділіть кількість слів відповідності на загальне число слів. Якщо результат більше або дорівнює фільтр твердість, у нас є дублікати матчу. Наприклад, "ABCD" і "CDE" мають відповідний відсоток 57 (4 слова відповідності, 7 всього слів). + + **Теги для сканування:** При використанні Слова типу сканування, ви можете вибрати теги, які будуть використовуватися для порівняння. + +.. only:: edition_se or edition_me + + **Слово зважування:** ЯКЩО ви вибрать Файл типу сканування, цею ВАРІАНТ Трохи змін, Як відповідній відсоток розраховується. При Слові зважування, Замість того, значення 1 в Дублікат Рахунка и загальна кількість слів, кожне слово має значення, рівну кількість сімволів, які смороду мають. При Слові зважування ", AB CDE FGHI" і "AB CDE fghij" матіме відповідній відсоток 53% (19 Персонажів, 10 сімволів, Що відповідає (4 для "б" і 6 "CDE")). + + **Матч Схожі слова:** ЯКЩО ви дозволите Цю опцію, подібні слова будуть зараховані Як сірники. Наприклад, "White Stripes" і "Біла смуга" буде збігатіся% з 100 Замість 66 з, Що функція включена. **Увага:** використову Цю опцію з обережністю. ЦІЛКОМ імовірно, Що ви отрімаєте Багато помилковості спрацьовувань в результатах при йо включенні. Тім не менше, Це Допоможи вам знайте дублікаті, Що ви НЕ знайшлі б в іншому випадка. Процес сканування кож однозначно повільніше, ця опція включена. + +.. only:: edition_pe + + **Тип сканування:** Цей параметр визначає тип сканування, які будуть зроблені на ваші картини. **Сканування** Зміст типу порівнює фактичний зміст фотографій нечіткі шляху (що робить його можна знайти не тільки точними копіями, але і подібні). **EXIF Timestamp** тип сканування дивиться на метадані EXIF з фото (якщо він існує) і відповідає фотографії, які мають такий же. Це набагато швидше, ніж сканування вмісту. **Увага:** Змінені фотографії часто тримають ж мітка EXIF, так що слідкуйте за помилкових спрацьовувань, коли ви використовуєте, що тип сканування. + + **Фільтра Твердість:** *Вміст тип сканування тільки*. Чим більше цей параметр, "важче" є фільтром (Іншими словами, тим менше результатів Ви отримаєте). Більшість фотографій одного й того ж матчу якості на 100%, навіть якщо формат відрізняється (PNG і JPG, наприклад.). Однак, якщо ви хочете, щоб відповідати PNG з більш низькою якістю JPG, вам доведеться встановити фільтром твердість нижче, ніж 100. За замовчуванням, 95, це солодке місце. + + **Матч малюнки різних розмірів:** Якщо ви встановите цей прапорець, фотографії різних розмірів буде дозволений в тому ж дублікат групи. + +**Можна змішувати файл виду:** Якщо ви встановите цей прапорець, дублювати групам дозволяється є файли з різними розширеннями. Якщо ви не перевірити його, ну, вони не є! + +**Ігнорувати дублікати hardlinking в той же файл:** Якщо ця опція включена, dupeGuru перевірить дублікати, щоб побачити якщо вони посилаються на той самий індексний +`дескриптор `__. Якщо вони це зроблять, вони не будуть вважатися дублікатами. (Тільки для OS X і Linux) + +**Використання регулярних виразів при фільтрації:** Якщо ви відзначите цей прапорець, фільтрація розглядатиме ваш запит фільтра, як **регулярний вираз**. Пояснюючи їх виходить за рамки цього документа. Гарне місце для початку навчання він `регулярного expressions.info `__. + +**Видалення порожніх папок після видалення або переміщення:** Коли ця опція включена, папки будуть видалені через файл видалений або переміщений і папка порожня. + +**Копіювання і переміщення:** Визначає, як операції копіювання та переміщення (в меню Дії) буде себе вести. + +* **Право на призначення:** Всі файли будуть відправлені безпосередньо в пункт призначення, не намагаючись відтворити початковий шлях взагалі. +* **Повторно відносний шлях:** шлях вихідний файл буде відтворений в папці призначення, аж до кореневого виділення в панелі Directories. Наприклад, якщо ви додали ``/Users/foobar/SomeFolder`` на панель Каталоги і переміщенні ``/Users/foobar/SomeFolder/SubFolder/SomeFile.ext`` до місця призначення ``/Users/foobar/MyDestination/SubFolder``, кінцевим пунктом призначення для файлу буде ``/Users/foobar/MyDestination/SubFolder`` (``SomeFolder`` були скорочені зі шляху джерела в кінцевий пункт призначення.). +* ** Повторно абсолютний шлях: ** шлях вихідний файл буде відтворений в папці призначення в повному комплекті. Наприклад, якщо ви переміщаєте ``/Users/foobar/SomeFolder/SubFolder/SomeFile.ext`` до місця призначення ``/Users/foobar/MyDestination``, кінцевим пунктом призначення для файлу буде ``/Users/foobar/MyDestination/Users/foobar/SomeFolder/SubFolder``. + +У всіх випадках, dupeGuru красиво ручки конфліктів імен шляхом додавання номера призначення ім'я файлу, якщо ім'я файлу вже існує в місці призначення. + +**Спеціальної команди:** Це перевагу визначає команду, яка буде викликатися "Викликати спеціальної команди" дії. Ви можете посилатися ні на які зовнішні програми через цю дію. Це може бути корисно, якщо, наприклад, у вас є хороший додаток порівнюєте встановлені. + +Формат команди такий же, як те, що ви повинні написати в командному рядку, за винятком того, що Є 2 заповнювачів: **%d** and **%r**. Ці наповнювачі будуть замінені на шлях вибраний обдурити (% г) і шлях до заслання на файл вибраного обдурити (%r). + +Якщо шлях до виконуваного містить прогалини, необхідно укласти його в "" лапки. Ви також повинні докласти заповнювачів в лапки, бо це дуже можливо, що шлях до обдурених і посилання будуть містити пробіли. Ось приклад користувальницької команди:: + + "C:\Program Files\SuperDiffProg\SuperDiffProg.exe" "%d" "%r" diff --git a/help/uk/_sources/quick_start.rst.txt b/help/uk/_sources/quick_start.rst.txt new file mode 100644 index 00000000..6e39aa58 --- /dev/null +++ b/help/uk/_sources/quick_start.rst.txt @@ -0,0 +1,14 @@ +Швидкий старт +============== + +Щоб ви швидко почали з dupeGuru, давайте просто робити сканування за допомогою стандартних параметрів за замовчуванням. + +* Запуск dupeGuru. +* Додавання папок для сканування або перетягнути & краплі або кнопку "+". +* Натисніть на сканування. +* Почекайте, поки процес сканування завершено. +* Подивіться на кожен дублікат (файли, які відступом) і переконайтеся, що це дійсно дублікат посиланням групи (файл вище дублювати без відступу та інвалідів вікна знак). +* Якщо файл помилкових дублікатів, виділіть її та натисніть **Дії -> Видалити вибрані з результатів**. +* Якщо ви впевнені, що немає помилкових дублікатів в результатах, натисніть на **Редагувати -> Позначити Всі**, а потім **Дії -> Отправить Позначено до кошику**. + +Це тільки основні сканування. Є багато налаштування ви можете зробити, щоб отримати різні результати і кілька методів вивчення та зміни ваших результатів. Щоб дізнатися про них, щойно прочитав решту цього файлу довідки. \ No newline at end of file diff --git a/help/uk/_sources/reprioritize.rst.txt b/help/uk/_sources/reprioritize.rst.txt new file mode 100644 index 00000000..d763464d --- /dev/null +++ b/help/uk/_sources/reprioritize.rst.txt @@ -0,0 +1,25 @@ +Повторне пріоритетів дублікатів +================================ + +dupeGuru намагається автоматично визначити, які дублікат повинен відправитися в заслання кожної групи +позиції, але іноді це робиться неправильно. У багатьох випадках, розумний обдурити сортування з "Цінності Дельта" +і "ошукані Тільки" варіанти на додаток до "Зробити вибраної посилання" дія робить трюк, але +іноді, більш потужний варіант не потрібно. Тут зміни пріоритетів в діалог вступає в +грати. Ви можете викликати його через "змінити пріоритети Результати" пункт в меню "Дії". + +Цей діалог дозволяє вам вибрати критерії, за якими посилання обдурити будуть відібрані в +кожній групі обдурити. Список доступних критеріїв зліва і перелік критеріїв ви +Обрана справа. + +Критеріїв категорії слідують аргумент. Наприклад, "Розмір (Вищий)" означає, що обдурити +з великим розміром переможе. "Властивості папки (/Foo/Bar)" означає, що ошукані в цій папці буде перемогти. для додавання +критерій правом списку, спочатку виберіть категорію в спадному списку і виберіть +subargument в наведеному нижче списку, а потім натисніть на праву стрілку кнопки. + +Порядок списку праворуч важливо (ви можете змінити порядок елементів через перетягнути і відпустити). коли +збір обдурити для довідки позицію, перший критерій використовується. Якщо є краватка, другий +критерій використовується і так далі і так далі. Наприклад, якщо ваші аргументи "Розмір (вищий)", а потім +"Файл (Не закінчується на номер)", заслання на файл, який буде обраний у групі буде +найбільших файл, а якщо два або декілька файлів мають однаковий розмір, який має ім'я файлу з +не закінчується номер буде використовуватися. Коли всі критерії привести до зв'язку, порядок, в якому ошукані +раніше були в групі буде використовуватися. \ No newline at end of file diff --git a/help/uk/_sources/results.rst.txt b/help/uk/_sources/results.rst.txt new file mode 100644 index 00000000..f015175a --- /dev/null +++ b/help/uk/_sources/results.rst.txt @@ -0,0 +1,101 @@ +Результати +=========== + +Коли dupeGuru завершення сканування на наявність дублікатів, він покаже його результати у вигляді дубліката список групи. + +Про дублікат групи +---------------------- + +Дублікат група являє собою групу файлів, які весь матч разом. Кожна група має **посиланням** на файл і одного або більше **однакових файлів**. Посилання файл перший файл групи. Його марка вікно вимкнено. Під ним, і з відступом, які дублікатів файлів. + +Ви можете відзначити дублікатів файлів, але ви ніколи не можете помітити посилання файл групи. Це захід безпеки, щоб запобігти dupeGuru від видалення не тільки повторювані файли, але їх посилання. Ти впевнений, що не хочу цього, чи не так? + +Що визначає, які файли посилання і які файли є дублікатами спочатку свою папку держави. Файл з посиланням папка завжди буде посилання в дублікат групи. Якщо всі файли зі звичайної папки, розмір визначити, який файл буде ведення дублікат групи. dupeGuru припускає, що ви завжди хочете зберегти найбільших файл, так що великих файлів займе вихідне положення. + +Ви можете змінити посилання файл групи вручну. Для цього виберіть дублікат файлу, який ви хочете просувати на посилання, і натисніть на кнопку **Дії -> Додати вибраної посилання**. + +Перегляд результатів +-------------------- + +Хоча ви можете просто натиснути на **Правка -> Виділити все, а потім** **Дії -> Отправить Позначено до кошику** швидко видалити всі дублікати файлів в результатах, завжди рекомендується переглянути всі дублікати перед видаляючи їх. + +Щоб допомогти вам огляд результатів, ви можете викликати панель **Докладніше**. Ця панель показує всі деталі обраного файла, а також подробиці свого заслання в. Це дуже зручно, щоб швидко визначити, якщо дублікат дійсно дублікат. Ви також можете двічі клацнути по файлу, щоб відкрити його і пов'язані з ним програми. + +Якщо у вас є більше помилкових дублікатів, ніж правда дублікатів (Якщо Ваш фільтр жорсткість дуже низька), кращий спосіб продовжити б переглянути дублікатів, знак істинного дублікати і натисніть **Дії -> Отправить Позначено до кошику** . Якщо у вас є більш вірно, ніж помилкових дублікатів дублікатів, замість цього можна позначити всі файли, які є помилковими дублікатів, а також використовувати **Дії -> Видалити Помічені від результатів**. + +Маркування і вибір +--------------------- + +**Зазначені** дублікат двох примірниках з невеликою прапорець поруч з ним, мають галочки. **Обрано** дублікат дубліката бути виділені. Кілька дій, вибір може бути виконана в dupeGuru стандартним чином (Shift/Command/Control клік). Ви можете перемикати знак стан всіх вибраних дублікати ", натиснувши **просторі**. + +Показати тільки ошукані +----------------------- + +Коли цей режим включений, дублікати відображаються без їх відповідного файлу довідки. Ви можете вибрати, марка і сортувати цей список, як і в звичайному режимі. + +DupeGuru результати, коли в нормальному режимі, сортуються відповідно до дублікат групи '**посиланням на файл**. Це означає, що якщо ви хочете, наприклад, щоб відзначити все дублікати "EXE" розширенням, ви не можете просто сортувати результати по "Вид", щоб мати всі EXE дублікатів разом, тому що група може складатися з більш ніж одного типу файлів . Ось де обдурені Тільки режим вступає в гру. Щоб позначити всі ваші "EXE" дублікати, ви просто повинні: + +* Включити ошукані Тільки режим. +* Додати "Вид" колонку "Стовпці" меню. +* Натисніть на те, що "Вид" колонки, щоб відсортувати список за типом. +* Знайдена перша дублікат з "EXE" роду. +* Виберіть його. +* Перейдіть, щоб знайти останнього дубліката з "EXE" роду. +* Утримуйте Shift і клацніть по ньому. +* Натисніть Space, щоб позначити всі вибрані дублікатів. + +Дельта значення +---------------- + +Якщо включити цей перемикач на деякі стовпці будуть відображати значення по відношенню до дубліката засланні, а не абсолютні значення. Ці дельти значення також будуть відображатися в різні кольори, щоб ви могли помітити їх легко. Наприклад, якщо дублікат 1,2 Мб і своє посилання в 1,4 Мб, розмір стовпець відображає -0,2 Мб. + +Тільки ошукані і Дельта значення +-------------------------------- + +Тільки ошукані режимі розкрити свою дійсну силу, коли ви використовуєте його з Delta Значення перемикач включений. Коли ви дозволите його, відносні значення буде відображатися замість абсолютних. Так що якщо, наприклад, ви хочете видалити з результатів всі дублікати, які є більш 300 Кб від їх посиланню, ви можете відсортувати дублікати тільки результати за розміром, виберіть всі дублікати при -300 в стовпці Розмір, видаляти їх, , а потім зробити те ж саме повторює більше 300 в нижній частині списку. + +Ви можете також використовувати його для зміни посилання пріоритет повторювані список. Коли ви робите свіжі сканування, якщо Є немає посилання папки, заслання на файл кожної групи є найбільшою файл. Якщо ви хочете змінити, що, наприклад, в останній модифікації час, ви можете відсортувати дублікати тільки результати за часом модифікації в **убування порядку** , виберіть всі дублікати з часом зміни дельти значення більше 0 і натисніть **Переконайтеся, обраної посилання**. Причина, чому ви повинні зробити порядок сортування за спаданням, тому що якщо 2 файли серед таких же дублікат групи вибираються при натисканні на **Зробити вибраної посилання**, тільки перший із списку будуть зроблені посилання, інші будуть проігноровані . І так як ви хочете Остання зміна файлу для посилання, які мають порядок сортування за спаданням запевняє вас, що першим пунктом у списку буде останньої зміни. + +.. todo:: Add "Non-numerical delta" information. + +Фільтрація +----------- + +dupeGuru підтримує після сканування, фільтрації. З його допомогою ви можете звузити результати, щоб ви могли виконувати дії, на підмножини. Наприклад, ви можете легко помітити всі дублікати з їх ім'я файлу, що містить "копіювати" з результатів за допомогою фільтра. + +.. todo:: Qt has a toolbar search field now, not a menu item. + +**Windows:** Для використання функції фільтрації, натисніть на Дії -> Застосувати фільтр, запишіть фільтр, який ви хочете застосувати і натисніть ОК. Щоб повернутися до нефільтроване результати, натисніть на Дії -> Скасувати фільтр. + +**Mac OS X:** Для використання функції фільтрації, тип фільтра в "Фільтр" поле пошуку на панелі інструментів. Щоб повернутися до нефільтроване результаті, очистіть поле, або натисніть на кнопку "X". + +У простому режимі (режим), що ви вводите в якості фільтра рядок, що використовується для виконання фактичної фільтрації, за винятком однієї маски: **\***. Таким чином, якщо ви введете "[*]" як ваш фільтр, він буде відповідати що-небудь з [] дужках в ньому, все, що між цими дужками. + +Для більш просунутих фільтрів, ви можете включити «Використання регулярних виразів при фільтрації" на. Функція фільтрації буде використовувати регулярні вирази. Регулярний вираз мови для узгодження тексту. Пояснюючи їх виходить за рамки цього документа. Гарне місце для початку навчання він `регулярного expressions.info `__. + +Матчі не чутливі до регістру, в простих і регулярних виразів режимі. + +Для фільтра, щоб відповідати, регулярний вираз не обов'язково має збігатися цілий файл, він просто зобов'язаний утримувати в ланцюжок, відповідну висловом. + +Ви могли помітити, що не всі дублікати в результаті будуть відповідати вашим фільтром. Це тому, що як тільки одна копія в матчах групового фільтра, то вся група залишиться в результатах, таким чином Ви можете мати більш чітке уявлення про дубліката контексті. Тим не менш, не відповідні дублікати у "заслання режимі". Таким чином, можна виконувати дії, як Марк все і обов'язково тільки знак фільтрується дублікатів. + +Дія меню +----------- + +* **Відкритий чорний список:** Видаліть всі ігнорують матчі ви додали. Ви повинні почати новий пошук знову очищується список ігнорованих щоб бути ефективними. +* **Експорт результатів в XHTML:** Візьміть поточні результати, а також створювати файл XHTML з нього. Стовпців, які видно при натисканні на цю кнопку буде стовпців у файлі XHTML. Файл автоматично відкриється в браузері за замовчуванням. +* **Надіслати Позначено в кошику:** Відправити всі відмічені дублікати, сміття, це очевидно. +* **Видалити Помічені і заміна з Жорсткі**: Передає всі відмічені дублікати, сміття, але після того, як зробили це, вилучені файли замінюються `жорстких `__ посилання до заслання на файл. (Тільки для OS X і Linux) +* **Переміщення Позначено в ...:** запросить призначення, а потім перемістити всі відмічені файли в тому, що призначення. Шлях вихідного файлу може бути відтворений в пункт призначення, залежно від "Копіювання і переміщення" переваги. +* **Скопіюйте Позначено в ...:** запитає у вас місце, а потім скопіювати всі вибрані файли до цього пункту призначення. Шлях вихідного файлу може бути відтворений в пункт призначення, залежно від "Копіювання і переміщення" переваги. +* **Видалити Помічені з результатів:** Видалити все відмічені дублікатів з результату пошуку. Самі файли не будуть порушені й залишаться, де вони. +* **Видалити вибрані з результатів:** Видалити всі вибрані дублікатів з результату пошуку. Зверніть увагу, що всі вибрані файли посилання будуть ігноруватися, тільки дублікати можуть бути видалені з цією дією. +* **Зробити Обраний Довідка:** Сприяння всі вибрані дублікатів посилання. Якщо дублікат частиною групи, що має посиланням на файл найближчі із заслання папки (в синій колір), не будуть прийняті заходи для цього дублікат. Якщо більш ніж один дублікат серед тієї ж групи обрані, тільки перший з кожної групи буде заохочуватися. +* **Додати обрані в чорний список:** Це спочатку видаляє всі вибрані дублікати з результатів, а потім додати матчу, які дублюють та опорний струм в чорний список. Цей матч не прийде знову в подальшої перевірки. Копіювати себе і, можливо, повернеться, але він буде шукатися в іншій посиланням на файл. Ви можете очистити список ігнорованих з Відкритий чорний список команди. +* **Відкрите Обраний з додатків за замовчунням:** Відкрийте файл за допомогою програми, пов'язаного з типом обраного файлу. +* **Розкривати Обраний в Finder:** Відкрийте папку, яка містить вибраний файл. +* **Викликати спеціальної команди:** Викликає зовнішню програму ви встановили в настройках з використанням виділеного фрагмента в якості аргументів у виклику. +* **Перейменування обрано:** Запит нове ім'я, а потім перейменувати вибраний файл. + +.. todo:: Add Move and iPhoto/iTunes warning +.. todo:: Add "Deletion Options" section. \ No newline at end of file diff --git a/help/uk/_static/ajax-loader.gif b/help/uk/_static/ajax-loader.gif new file mode 100644 index 00000000..61faf8ca Binary files /dev/null and b/help/uk/_static/ajax-loader.gif differ diff --git a/help/uk/_static/alert_info_32.png b/help/uk/_static/alert_info_32.png new file mode 100644 index 00000000..ea4d1baf Binary files /dev/null and b/help/uk/_static/alert_info_32.png differ diff --git a/help/uk/_static/alert_warning_32.png b/help/uk/_static/alert_warning_32.png new file mode 100644 index 00000000..a687c3dc Binary files /dev/null and b/help/uk/_static/alert_warning_32.png differ diff --git a/help/uk/_static/basic.css b/help/uk/_static/basic.css new file mode 100644 index 00000000..c7adab45 --- /dev/null +++ b/help/uk/_static/basic.css @@ -0,0 +1,665 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 59em; + max-width: 70em; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/help/uk/_static/bg-page.png b/help/uk/_static/bg-page.png new file mode 100644 index 00000000..fe0a6dc8 Binary files /dev/null and b/help/uk/_static/bg-page.png differ diff --git a/help/uk/_static/bullet_orange.png b/help/uk/_static/bullet_orange.png new file mode 100644 index 00000000..1cb8097c Binary files /dev/null and b/help/uk/_static/bullet_orange.png differ diff --git a/help/uk/_static/comment-bright.png b/help/uk/_static/comment-bright.png new file mode 100644 index 00000000..15e27edb Binary files /dev/null and b/help/uk/_static/comment-bright.png differ diff --git a/help/uk/_static/comment-close.png b/help/uk/_static/comment-close.png new file mode 100644 index 00000000..4d91bcf5 Binary files /dev/null and b/help/uk/_static/comment-close.png differ diff --git a/help/uk/_static/comment.png b/help/uk/_static/comment.png new file mode 100644 index 00000000..dfbc0cbd Binary files /dev/null and b/help/uk/_static/comment.png differ diff --git a/help/uk/_static/doctools.js b/help/uk/_static/doctools.js new file mode 100644 index 00000000..0c15c009 --- /dev/null +++ b/help/uk/_static/doctools.js @@ -0,0 +1,311 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var bbox = span.getBBox(); + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + var parentOfText = node.parentNode.parentNode; + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); \ No newline at end of file diff --git a/help/uk/_static/documentation_options.js b/help/uk/_static/documentation_options.js new file mode 100644 index 00000000..ec2fd0df --- /dev/null +++ b/help/uk/_static/documentation_options.js @@ -0,0 +1,9 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: '', + VERSION: '4.0.3', + LANGUAGE: 'uk', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' +}; \ No newline at end of file diff --git a/help/uk/_static/down-pressed.png b/help/uk/_static/down-pressed.png new file mode 100644 index 00000000..5756c8ca Binary files /dev/null and b/help/uk/_static/down-pressed.png differ diff --git a/help/uk/_static/down.png b/help/uk/_static/down.png new file mode 100644 index 00000000..1b3bdad2 Binary files /dev/null and b/help/uk/_static/down.png differ diff --git a/help/uk/_static/file.png b/help/uk/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/help/uk/_static/file.png differ diff --git a/help/uk/_static/haiku.css b/help/uk/_static/haiku.css new file mode 100644 index 00000000..75af2a5c --- /dev/null +++ b/help/uk/_static/haiku.css @@ -0,0 +1,376 @@ +/* + * haiku.css_t + * ~~~~~~~~~~~ + * + * Sphinx stylesheet -- haiku theme. + * + * Adapted from http://haiku-os.org/docs/Haiku-doc.css. + * Original copyright message: + * + * Copyright 2008-2009, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Francois Revol + * Stephan Assmus + * Braden Ewing + * Humdinger + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +html { + margin: 0px; + padding: 0px; + background: #FFF url(bg-page.png) top left repeat-x; +} + +body { + line-height: 1.5; + margin: auto; + padding: 0px; + font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; + min-width: 59em; + max-width: 70em; + color: #333333; +} + +div.footer { + padding: 8px; + font-size: 11px; + text-align: center; + letter-spacing: 0.5px; +} + +/* link colors and text decoration */ + +a:link { + font-weight: bold; + text-decoration: none; + color: #dc3c01; +} + +a:visited { + font-weight: bold; + text-decoration: none; + color: #892601; +} + +a:hover, a:active { + text-decoration: underline; + color: #ff4500; +} + +/* Some headers act as anchors, don't give them a hover effect */ + +h1 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h2 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h3 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +h4 a:hover, a:active { + text-decoration: none; + color: #0c3762; +} + +a.headerlink { + color: #a7ce38; + padding-left: 5px; +} + +a.headerlink:hover { + color: #a7ce38; +} + +/* basic text elements */ + +div.content { + margin-top: 20px; + margin-left: 40px; + margin-right: 40px; + margin-bottom: 50px; + font-size: 0.9em; +} + +/* heading and navigation */ + +div.header { + position: relative; + left: 0px; + top: 0px; + height: 85px; + /* background: #eeeeee; */ + padding: 0 40px; +} +div.header h1 { + font-size: 1.6em; + font-weight: normal; + letter-spacing: 1px; + color: #0c3762; + border: 0; + margin: 0; + padding-top: 15px; +} +div.header h1 a { + font-weight: normal; + color: #0c3762; +} +div.header h2 { + font-size: 1.3em; + font-weight: normal; + letter-spacing: 1px; + text-transform: uppercase; + color: #aaa; + border: 0; + margin-top: -3px; + padding: 0; +} + +div.header img.rightlogo { + float: right; +} + + +div.title { + font-size: 1.3em; + font-weight: bold; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-bottom: 25px; +} +div.topnav { + /* background: #e0e0e0; */ +} +div.topnav p { + margin-top: 0; + margin-left: 40px; + margin-right: 40px; + margin-bottom: 0px; + text-align: right; + font-size: 0.8em; +} +div.bottomnav { + background: #eeeeee; +} +div.bottomnav p { + margin-right: 40px; + text-align: right; + font-size: 0.8em; +} + +a.uplink { + font-weight: normal; +} + + +/* contents box */ + +table.index { + margin: 0px 0px 30px 30px; + padding: 1px; + border-width: 1px; + border-style: dotted; + border-color: #e0e0e0; +} +table.index tr.heading { + background-color: #e0e0e0; + text-align: center; + font-weight: bold; + font-size: 1.1em; +} +table.index tr.index { + background-color: #eeeeee; +} +table.index td { + padding: 5px 20px; +} + +table.index a:link, table.index a:visited { + font-weight: normal; + text-decoration: none; + color: #dc3c01; +} +table.index a:hover, table.index a:active { + text-decoration: underline; + color: #ff4500; +} + + +/* Haiku User Guide styles and layout */ + +/* Rounded corner boxes */ +/* Common declarations */ +div.admonition { + -webkit-border-radius: 10px; + -khtml-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; + border-style: dotted; + border-width: thin; + border-color: #dcdcdc; + padding: 10px 15px 10px 15px; + margin-bottom: 15px; + margin-top: 15px; +} +div.note { + padding: 10px 15px 10px 80px; + background: #e4ffde url(alert_info_32.png) 15px 15px no-repeat; + min-height: 42px; +} +div.warning { + padding: 10px 15px 10px 80px; + background: #fffbc6 url(alert_warning_32.png) 15px 15px no-repeat; + min-height: 42px; +} +div.seealso { + background: #e4ffde; +} + +/* More layout and styles */ +h1 { + font-size: 1.3em; + font-weight: bold; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-top: 30px; +} + +h2 { + font-size: 1.2em; + font-weight: normal; + color: #0c3762; + border-bottom: dotted thin #e0e0e0; + margin-top: 30px; +} + +h3 { + font-size: 1.1em; + font-weight: normal; + color: #0c3762; + margin-top: 30px; +} + +h4 { + font-size: 1.0em; + font-weight: normal; + color: #0c3762; + margin-top: 30px; +} + +p { + text-align: justify; +} + +p.last { + margin-bottom: 0; +} + +ol { + padding-left: 20px; +} + +ul { + padding-left: 5px; + margin-top: 3px; +} + +li { + line-height: 1.3; +} + +div.content ul > li { + -moz-background-clip:border; + -moz-background-inline-policy:continuous; + -moz-background-origin:padding; + background: transparent url(bullet_orange.png) no-repeat scroll left 0.45em; + list-style-image: none; + list-style-type: none; + padding: 0 0 0 1.666em; + margin-bottom: 3px; +} + +td { + vertical-align: top; +} + +code { + background-color: #e2e2e2; + font-size: 1.0em; + font-family: monospace; +} + +pre { + border-color: #0c3762; + border-style: dotted; + border-width: thin; + margin: 0 0 12px 0; + padding: 0.8em; + background-color: #f0f0f0; +} + +hr { + border-top: 1px solid #ccc; + border-bottom: 0; + border-right: 0; + border-left: 0; + margin-bottom: 10px; + margin-top: 20px; +} + +/* printer only pretty stuff */ +@media print { + .noprint { + display: none; + } + /* for acronyms we want their definitions inlined at print time */ + acronym[title]:after { + font-size: small; + content: " (" attr(title) ")"; + font-style: italic; + } + /* and not have mozilla dotted underline */ + acronym { + border: none; + } + div.topnav, div.bottomnav, div.header, table.index { + display: none; + } + div.content { + margin: 0px; + padding: 0px; + } + html { + background: #FFF; + } +} + +.viewcode-back { + font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; + margin: -1px -10px; + padding: 0 12px; +} + +/* math display */ +div.math p { + text-align: center; +} \ No newline at end of file diff --git a/help/uk/_static/jquery-3.2.1.js b/help/uk/_static/jquery-3.2.1.js new file mode 100644 index 00000000..d2d8ca47 --- /dev/null +++ b/help/uk/_static/jquery-3.2.1.js @@ -0,0 +1,10253 @@ +/*! + * jQuery JavaScript Library v3.2.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2017-03-20T18:59Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.2.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Simple selector that can be filtered directly, removing non-Elements + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + // Complex selector, compare the two sets, removing non-Elements + qualifier = jQuery.filter( qualifier, elements ); + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( jQuery.isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ jQuery.camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( jQuery.camelCase ); + } else { + key = jQuery.camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( ">tbody", elem )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i, + val = 0; + + // If we already have the right measurement, avoid augmentation + if ( extra === ( isBorderBox ? "border" : "content" ) ) { + i = 4; + + // Otherwise initialize for horizontal or vertical properties + } else { + i = name === "width" ? 1 : 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with computed style + var valueIsBorderBox, + styles = getStyles( elem ), + val = curCSS( elem, name, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Fall back to offsetWidth/Height when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + if ( val === "auto" ) { + val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + } + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnothtmlwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, isFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + + +
+ + +
+

Changelog

+

About the word «crash»: When reading this changelog, you might be alarmed at the number of fixes +for «crashes». Be aware that when the word «crash» is used here, it refers to «soft crashes» which +don’t cause the application to quit. You simply get an error window that asks you if you want to +send the crash report to Hardcoded Software. Crashes that cause the application to quit are called +«hard crashes» in this changelog.

+
+

4.0.3 (2016-11-24)

+
    +
  • Add new picture cache backend: shelve
  • +
  • Make shelve picture cache backend the active one on MacOS to fix #394 more +elegantly. [cocoa]
  • +
  • Remove Sparkle (auto-updates) due to technical limitations. [cocoa]
  • +
+
+
+

4.0.2 (2016-10-09)

+
    +
  • Fix systematic crash in Picture Mode under MacOS Sierra. (#394)
  • +
  • No change for Linux. Just keeping version in sync.
  • +
+
+
+

4.0.1 (2016-08-24)

+
    +
  • Add Greek localization, by Gabriel Koutilellis. (#382)
  • +
  • Fix localization base path. [qt] (#378)
  • +
  • Fix broken load results dialog. [qt]
  • +
  • Fix crash on load results. [cocoa] (#380)
  • +
  • Save preferences more predictably. [qt] (#379)
  • +
  • Fix picture mode’s fuzzy block scanner threshold. (#387)
  • +
+
+
+

4.0.0 (2016-07-01)

+
    +
  • Merge Standard, Music and Picture editions in the same application!
  • +
  • Improve documentation. (#294)
  • +
  • Add Polish, Korean, Spanish and Dutch localizations.
  • +
  • qt: Fix wrong use_regexp option propagation to core. (#295)
  • +
  • qt: Fix progress window mistakenly showing up on startup. (#357)
  • +
  • Bump Python requirement to v3.4.
  • +
  • Bump OS X requirement to 10.8
  • +
  • Drop Windows support, maybe temporarily. +Details <https://www.hardcoded.net/archive2015`#2015-11-01>`_
  • +
  • cocoa: Drop iPhoto, Aperture and iTunes support. Was unmaintained and obsolete.
  • +
  • Drop «Audio Contents» scan type. Was confusing and seldom useful.
  • +
  • Change license to GPLv3
  • +
+
+
+

3.9.1 (2014-10-17)

+
    +
  • Fixed AttributeError: 'ComboboxModel' object has no attribute 'reset'. [Linux, Windows] (#254)
  • +
  • Fixed PermissionError on saving results. (#266)
  • +
  • Fixed a build problem introduced by Sphinx 1.2.3.
  • +
  • Updated German localisation, by Frank Weber.
  • +
+
+
+

3.9.0 (2014-04-19)

+
    +
  • This is mostly a dependencies upgrade.
  • +
  • Upgraded to Python 3.3.
  • +
  • Upgraded to Qt 5.
  • +
  • Minimum Windows version is now Windows 7 64bit.
  • +
  • Minimum Ubuntu version is now 14.04.
  • +
  • Minimum OS X version is now 10.7 (Lion).
  • +
  • … But with a couple of little improvements.
  • +
  • Improved documentation.
  • +
  • Overwrite subfolders“ state when setting states in folder dialog (#248)
  • +
  • The error report dialog now brings the user to Github issues.
  • +
+
+
+

3.8.0 (2013-12-07)

+
    +
  • Disable symlink/hardlink deletion option when not relevant. (#247)
  • +
  • Make Cmd+A select all folders in the Folder Selection dialog. [Mac] (#228)
  • +
  • Make non-numeric delta comparison case insensitive. (#239)
  • +
  • Fix surrogate-related UnicodeEncodeError on CSV export. (#210)
  • +
  • Fixed crash on Dupe Count sorting with Delta + Dupes Only. (#238)
  • +
  • Improved documentation.
  • +
  • Important internal refactorings.
  • +
  • Dropped Ubuntu 12.04 and 12.10 support.
  • +
  • Removed the fairware dialog (More Info).
  • +
+
+
+

3.7.1 (2013-08-19)

+
    +
  • Fixed folder scan type, which was broken in v3.7.0.
  • +
+
+
+

3.7.0 (2013-08-17)

+
    +
  • Improved delta values to support non-numerical values. (#213)
  • +
  • Improved the Re-Prioritize dialog’s UI. (#224)
  • +
  • Added hardlink/symlink support on Windows Vista+. (#220)
  • +
  • Dropped 32bit support on Mac OS X.
  • +
  • Added Vietnamese localization by Phan Anh.
  • +
+
+
+

3.6.1 (2013-04-28)

+
    +
  • Improved «Make Selection Reference» to make it clearer. (#222)
  • +
  • Improved «Open Selected» to allow opening more than one file at once. (#142)
  • +
  • Fixed a few typos here and there. (#216 #225)
  • +
  • Tweaked the fairware dialog (More Info).
  • +
  • Added Arch Linux packaging
  • +
  • Added a 64-bit build for Windows.
  • +
  • Improved Russian localization by Kyrill Detinov.
  • +
  • Improved Brazilian localization by Victor Figueiredo.
  • +
+
+
+

3.6.0 (2012-08-08)

+
    +
  • Added «Export to CSV». (#189)
  • +
  • Added «Replace with symlinks» to complement «Replace with hardlinks». [Mac, Linux] (#194)
  • +
  • dupeGuru now tells how many duplicates were affected after each re-prioritization operation. (#204)
  • +
  • Added Longest/Shortest filename criteria in the re-prioritize dialog. (#198)
  • +
  • Fixed result table cells which mistakenly became writable in v3.5.0. [Mac] (#203)
  • +
  • Fixed «Rename Selected» which was broken since v3.5.0. [Mac] (#202)
  • +
  • Fixed a bug where «Reset to Defaults» in the Columns menu wouldn’t refresh menu items“ marked state.
  • +
  • Added Brazilian localization by Victor Figueiredo.
  • +
+
+
+

3.5.0 (2012-06-01)

+
    +
  • Added a Deletion Options panel.
  • +
  • Greatly improved memory usage for big scans.
  • +
  • Added a keybinding for the filter field. (#182) [Mac]
  • +
  • Upgraded minimum requirements for Ubuntu to 12.04.
  • +
+
+
+

3.4.1 (2012-04-14)

+
    +
  • Fixed the «Folders» scan type. [Mac]
  • +
  • Fixed localization issues. [Windows, Linux]
  • +
+
+
+

3.4.0 (2012-03-29)

+
    +
  • Improved results window UI. [Windows, Linux]
  • +
  • Added a dialog to edit the Ignore List.
  • +
  • Added the ability to sort results by «marked» status.
  • +
  • Fixed «Open with default application». (#190)
  • +
  • Fixed a bug where there would be a false reporting of discarded matches. (#195)
  • +
  • Fixed various localization glitches.
  • +
  • Fixed hard crashes on crash reporting. (#196)
  • +
  • Fixed bug where the details panel would show up at inconvenient places in the screen. [Windows, Linux]
  • +
+
+
+

3.3.3 (2012-02-01)

+
    +
  • Fixed crash on adding some folders. [Mac OS X]
  • +
  • Added Ukrainian localization by Yuri Petrashko.
  • +
+
+
+

3.3.2 (2012-01-16)

+
    +
  • Fixed random hard crashes (yeah, again). [Mac OS X]
  • +
  • Fixed crash on Export to HTML. [Windows, Linux]
  • +
  • Added Armenian localization by Hrant Ohanyan.
  • +
  • Added Russian localization by Igor Pavlov.
  • +
+
+
+

3.3.1 (2011-12-02)

+
    +
  • Fixed a couple of nasty crashes.
  • +
+
+
+

3.3.0 (2011-11-30)

+
    +
  • Added multiple-selection in folder selection dialog for a more efficient folder removal. (#179)
  • +
  • Fixed a crash in the prioritize dialog. (#178)
  • +
  • Fixed a bug where mass marking with a filter would mark more than filtered duplicates. (#181)
  • +
  • Fixed random hard crashes. [Mac OS X] (#183 #184)
  • +
  • Added Czech localization by Aleš Nehyba.
  • +
  • Added Italian localization by Paolo Rossi.
  • +
+
+
+

3.2.1 (2011-10-02)

+
    +
  • Fixed a couple of broken action bindings from v3.2.0.
  • +
+
+
+

3.2.0 (2011-09-27)

+
    +
  • Added duplicate re-prioritization dialog. (#138)
  • +
  • Added font size preference for duplicate table. (#82)
  • +
  • Added Quicklook support. [Mac OS X] (#21)
  • +
  • Improved behavior of Mark Selected. (#139)
  • +
  • Improved filename sorting. (#169)
  • +
  • Added Chinese (Simplified) localization by Eric Dee.
  • +
  • Tweaked the fairware system.
  • +
  • Upgraded minimum requirements to OS X 10.6 and Ubuntu 11.04.
  • +
+
+
+

3.1.2 (2011-08-25)

+
    +
  • Fixed a bug preventing the Folders scan from working. (#172)
  • +
+
+
+

3.1.1 (2011-08-24)

+
    +
  • Added German localization by Gregor Tätzner.
  • +
  • Improved OS X Lion compatibility. [Mac OS X]
  • +
  • Made the file collection phase cancellable. (#168)
  • +
  • Fixed glitch in folder window upon selecting a folder state. [Windows, Linux] (#165)
  • +
  • Fixed a text coloring glitch in the results. (#156)
  • +
  • Fixed glitch in the sorting feature of the Folder column. (#161)
  • +
  • Make sure that saved results have the «.dupeguru» extension. [Linux] (#157)
  • +
+
+
+

3.1.0 (2011-04-16)

+
    +
  • Added the «Folders» scan type. (#89)
  • +
  • Fixed a couple of crashes. (#140 #149)
  • +
+
+
+

3.0.2 (2011-03-16)

+
    +
  • Fixed crash after removing marked dupes. (#140)
  • +
  • Fixed crash on error handling. [Windows] (#144)
  • +
  • Fixed crash on copy/move. [Windows] (#148)
  • +
  • Fixed crash when launching dupeGuru from a very long folder name. [Mac OS X] (#119)
  • +
  • Fixed a refresh bug in directory panel. (#153)
  • +
  • Improved reliability of the «Send to Trash» operation. [Linux]
  • +
  • Tweaked Fairware reminders.
  • +
+
+
+

3.0.1 (2011-01-27)

+
    +
  • Restored the context menu which had been broken in 3.0.0. [Mac OS X] (#133)
  • +
  • Fixed a bug where an «unsaved results» warning would be issued on quit even with empty results. (#134)
  • +
  • Removed focus from the cancel button in the progress dialog to avoid accidental cancellations. [Mac OS X] (#135)
  • +
  • Folders added through drag and drop are added to the recent folders list. (#136)
  • +
  • Added a debugging mode. (#132)
  • +
  • Fixed french localization glitches.
  • +
+
+
+

3.0.0 (2011-01-24)

+
    +
  • Re-designed the UI. (#129)
  • +
  • Internationalized dupeGuru and localized it to french. (#32)
  • +
  • Changed the format of the help file. (#130)
  • +
+
+
+

2.12.3 (2011-01-01)

+
    +
  • Fixed bug causing results to be corrupted after a scan cancellation. (#120)
  • +
  • Fixed crash when fetching Fairware unpaid hours. (#121)
  • +
  • Fixed crash when replacing files with hardlinks. (#122)
  • +
+
+
+

2.12.2 (2010-10-05)

+
    +
  • Fixed delta column colors which were broken since 2.12.0.
  • +
  • Fixed column sorting crash. (#108)
  • +
  • Fixed occasional crash during scan. (#106)
  • +
+
+
+

2.12.1 (2010-09-30)

+
    +
  • Re-licensed dupeGuru to BSD and made it Fairware.
  • +
+
+
+

2.12.0 (2010-09-26)

+
    +
  • Improved UI with a little revamp.
  • +
  • Added the possibility to place hardlinks to references after having deleted duplicates. [Mac OS X, Linux] (#91)
  • +
  • Added an option to ignore duplicates hardlinking to the same file. [Mac OS X, Linux] (#92)
  • +
  • Added multiple selection in the «Add Directory» dialog. [Mac OS X] (#105)
  • +
  • Fixed a bug preventing drag & drop from working in the Directories panel. [Windows, Linux]
  • +
+
+
+

2.11.1 (2010-08-26)

+
    +
  • Fixed HTML exporting which was broken in 2.11.0.
  • +
+
+
+

2.11.0 (2010-08-18)

+
    +
  • Added the ability to save results (and reload them) at arbitrary locations.
  • +
  • Improved the way reference files in dupe groups are chosen. (#15)
  • +
  • Remember size/position of all windows between launches. (#102)
  • +
  • Fixed a bug sometimes preventing dupeGuru from reloading previous results.
  • +
  • Fixed a bug sometimes causing the progress dialog to be stuck there. [Mac OS X] (#103)
  • +
  • Removed the Creation Date column, which wasn’t displaying the correct value anyway. (#101)
  • +
+
+
+

2.10.1 (2010-07-15)

+ +
+
+

2.10.0 (2010-04-13)

+
    +
  • Improved error messages when files can’t be sent to trash, moved or copied.
  • +
  • Added a custom command invocation action. (#12)
  • +
  • Filters are now applied on whole paths. (#4)
  • +
+
+
+

2.9.2 (2010-02-10)

+
    +
  • dupeGuru is now 64-bit on Mac OS X!
  • +
  • Fixed a crash upon quitting when support folder is not present. (#83)
  • +
  • Fixed a crash during sorting. (#85)
  • +
  • Fixed selection glitches, especially while renaming. (#93)
  • +
+
+
+

2.9.1 (2010-01-13)

+
    +
  • Improved memory usage for Contents scans. (#75)
  • +
  • Improved scanning speed when ref directories are involved. (#77)
  • +
  • Show a message dialog at the end of the scan if no duplicates are found. (#81)
  • +
  • Fixed a bug sometimes causing the small files threshold pref to be ignored. [Mac OS X] (#75)
  • +
+
+
+

2.9.0 (2009-11-03)

+
    +
  • Significantly improved speed and memory usage of big contents-based scans.
  • +
  • Added drag & drop support in the Directories panel. (#9)
  • +
  • Fixed a bug causing dupeGuru to be confused if a scanned file was moved during the scan. (#72)
  • +
  • Dropped support for Mac OS X 10.4 (Tiger)
  • +
+
+
+

2.8.2 (2009-10-14)

+
    +
  • Improved directory selection in the Directories panel (Windows). (#56)
  • +
  • Fixed a bug preventing dupeGuru from starting on certain machines (Windows). (#68)
  • +
  • Fixed a crash during very big scans. (#70)
  • +
+
+
+

2.8.1 (2009-10-02)

+
    +
  • Fixed crash with filtering when regular expressions were enabled. (#60)
  • +
  • Fixed crash when setting directories“ state. (Mac OS X) (#66)
  • +
  • Fixed crash with Make Reference when certain filters are applied. (Mac OS X) (#55)
  • +
  • Improved error handling during delete/move/copy actions. (#62 #65)
  • +
+
+
+

2.8.0 (2009-09-07)

+
    +
  • Added support for all kinds of bundle (not just applications) (Mac OS X) (#11)
  • +
  • Re-introduced the Export to XHTML feature to Windows. (#14)
  • +
  • Improved Export to XHTML speed. (#14)
  • +
  • Improved Contents scanning speed for large files. (#33)
  • +
  • Improved the grouping algorithm to reduce the number of discarded files in non-exact scans. (#51)
  • +
  • Stopped showing the same file on the 2 sides of the details panel when a ref file is selected. (#50)
  • +
  • Fixed crashes in the Directories panel. (#46)
  • +
+
+
+

2.7.3 (2009-06-20)

+
    +
  • +
    Fixed bugs with selection being jumpy during «Make Reference» actions and Power Marker
    +
    switches. (#3)
    +
    +
  • +
  • Fixed crash happening when a file with non-roman characters couldn’t be analyzed. (#30)
  • +
  • Fixed crash sometimes happening during the file collection phase in scanning. (#38)
  • +
  • Restored double-click and right-click behavior lost in the PyQt move (Windows). (#34 #35)
  • +
+
+
+

2.7.2 (2009-06-10)

+
    +
  • Fixed an occasional crash on Copy/Move operations. (#16)
  • +
  • Added automatic exclusion for sensible folders (like system folders). (#20)
  • +
  • Fixed an occasional crash when application files were part of the results (Mac OS X). (#25)
  • +
+
+
+

2.7.1 (2009-05-29)

+
    +
  • Fixed a bug causing crashes when having application files in the results.
  • +
  • Fixed a bug causing a GUI freeze at the beginning of a scan with a lot of files.
  • +
  • Fixed a bug that sometimes caused a crash when an action was cancelled, and then started again.
  • +
+
+
+

2.7.0 (2009-05-25)

+
    +
  • Converted the Windows GUI to Qt.
  • +
  • Improved the reliability of the scanning process.
  • +
+
+
+

2.6.1 (2009-03-27)

+
    +
  • Fixed an occasional crash caused by permission issues.
  • +
  • +
    Fixed a bug where the «X discarded» notice would show a too large number of discarded
    +
    duplicates.
    +
    +
  • +
+
+
+

2.6.0 (2008-09-10)

+
    +
  • Added a small file threshold preference.
  • +
  • Added a notice in the status bar when matches were discarded during the scan.
  • +
  • Improved duplicate prioritization (smartly chooses which file you will keep).
  • +
  • Improved scan progress feedback.
  • +
  • Improved responsiveness of the user interface for certain actions.
  • +
+
+
+

2.5.4 (2008-08-10)

+
    +
  • Improved the speed of results loading and saving.
  • +
  • Fixed a crash sometimes occurring during duplicate deletion.
  • +
+
+
+

2.5.3 (2008-07-08)

+
    +
  • Improved unicode handling for filenames. dupeGuru will now find a lot more duplicates if your files have non-ascii characters in it.
  • +
  • Fixed «Clear Ignore List» crash in Windows.
  • +
+
+
+

2.5.2 (2008-01-10)

+
    +
  • Improved the handling of low memory situations.
  • +
  • Improved the directory panel. The «Remove» button changes to «Put Back» when an excluded directory is selected.
  • +
  • Improved scan, delete and move speed in situations where there were a lot of duplicates.
  • +
  • Fixed occasional crashes when moving bundles (such as .app files).
  • +
  • Fixed occasional crashes when moving a lot of files at once.
  • +
+
+
+

2.5.1 (2007-11-22)

+
    +
  • Added the «Remove empty folders» option.
  • +
  • Fixed results load/save issues.
  • +
  • Fixed occasional status bar inaccuracies when the results are filtered.
  • +
+
+
+

2.5.0 (2007-09-15)

+
    +
  • Added post scan filtering.
  • +
  • Fixed issues with the rename feature under Windows
  • +
  • Fixed some user interface annoyances under Windows
  • +
+
+
+

2.4.8 (2007-04-14)

+
    +
  • Improved UI responsiveness (using threads) under Mac OS X.
  • +
  • Improved result load/save speed and memory usage.
  • +
+
+
+

2.4.7 (2007-03-10)

+
    +
  • Fixed a «bad file descriptor» error occasionally popping up.
  • +
  • Fixed a bug with non-latin directory names.
  • +
+
+
+

2.4.6 (2007-02-10)

+
    +
  • Added Re-orderable columns. In fact, I re-added the feature which was lost in the C# conversion in 2.4.0 (Windows).
  • +
  • Changed the behavior of the scanning engine when setting the hardness to 100. It will now only match files that have their words in the same order.
  • +
  • Fixed a bug with all the Delete/Move/Copy actions with certain kinds of files.
  • +
+
+
+

2.4.5 (2007-01-11)

+
    +
  • Fixed a bug with the Move action.
  • +
+
+
+

2.4.4 (2007-01-07)

+
    +
  • Fixed a «ghosting» bug. Dupes deleted by dupeGuru would sometimes come back in subsequent scans (Windows).
  • +
  • Fixed bugs sometimes making dupeGuru crash when marking a dupe (Windows).
  • +
  • Fixed some minor visual glitches (Windows).
  • +
+
+
+

2.4.3 (2006-12-08)

+
    +
  • Fixed a mishandling of «.app» files (OS X).
  • +
  • Fixed a bug preventing files from «reference» directories to be displayed in blue in the results (Windows).
  • +
  • Fixed a bug preventing some files to be sent to the recycle bin (Windows).
  • +
  • Fixed a bug in the packaging preventing certain Windows configurations to start dupeGuru at all.
  • +
+
+
+

2.4.2 (2006-11-18)

+
    +
  • Fixed a bug with directory states.
  • +
+
+
+

2.4.1 (2006-11-15)

+
    +
  • Fixed a bug causing the ignore list not to be saved.
  • +
  • Fixed a bug sometimes making delete and move operations stall.
  • +
+
+
+

2.4.0 (2006-11-10)

+
    +
  • Changed the Windows interface. It is now .NET based.
  • +
  • Added an auto-update feature to the windows version.
  • +
  • Changed the way power marking works. It is now a mode instead of a separate window.
  • +
  • Changed the «Size (MB)» column for a «Size (KB)» column. The values are now «ceiled» instead of rounded. Therefore, a size «0» is now really 0 bytes, not just a value too small to be rounded up. It is also the case for delta values.
  • +
  • Removed the min word length/count options. These came from Mp3 Filter, and just aren’t used anymore. Word weighting does pretty much the same job.
  • +
+
+
+

2.3.4 (2006-11-07)

+
    +
  • Improved speed and memory usage of the scanning engine, again. Does it mean there was a lot of improvements to be made? Nah…
  • +
+
+
+

2.3.3 (2006-11-02)

+
    +
  • Improved speed and memory usage of the scanning engine, especially when the scan results in a lot of duplicates.
  • +
  • Now I wonder if Sparkle is going to work well…
  • +
+
+
+

2.3.2 (2006-10-16)

+
    +
  • Added an auto-update feature in the Mac OS X version (with Sparkle).
  • +
  • Fixed a bug preventing some duplicate reports to be created correctly under Windows.
  • +
+
+
+

2.3.1 (2006-10-02)

+
    +
  • Fixed a bug preventing some duplicates to be found, especially when scanning lots of files.
  • +
+
+
+

2.3.0 (2006-09-22)

+
    +
  • Added XHTML export feature.
  • +
+
+
+

2.2.10 (2006-08-31)

+
    +
  • Added sticky columns.
  • +
  • Fixed an issue with file caching between scans.
  • +
  • Fixed an issue preventing some duplicates from being deleted/moved/copied.
  • +
+
+
+

2.2.9 (2006-08-27)

+
    +
  • Fixed an issue with ignore list and unicode.
  • +
  • Fixed an issue with file attribute fetching sometimes causing dupeGuru to crash.
  • +
  • Fixed an issue in the directories panel under Windows.
  • +
+
+
+

2.2.8 (2006-08-17)

+
    +
  • Fixed an issue in the duplicate seeking engine preventing some duplicates to be found.
  • +
+
+
+

2.2.7 (2006-08-12)

+
    +
  • Improved unicode support.
  • +
  • Improved the «Reveal in Finder» («Open Containing Folder» in Windows) feature so it selects the file in the folder it opens.
  • +
+
+
+

2.2.6 (2006-08-07)

+
    +
  • Improved the ignore list system.
  • +
  • dupeGuru is now a Universal application on Mac OS X.
  • +
+
+
+

2.2.5 (2006-07-26)

+
    +
  • Improved application (.app) dupe detection on Mac OS X.
  • +
  • Fixed an issue that occasionally made dupeGuru crash on startup.
  • +
+
+
+

2.2.4 (2006-06-27)

+
    +
  • Fixed an issue with Move and Copy features.
  • +
+
+
+

2.2.3 (2006-06-15)

+
    +
  • Improved duplicate scanning speed.
  • +
  • Added a warning that a file couldn’t be renamed if a file with the same name already exists.
  • +
+
+
+

2.2.2 (2006-06-07)

+
    +
  • Added «Rename Selected» feature.
  • +
  • Fixed some minor issues with «Reload Last Results» feature.
  • +
  • Fixed ignore list issues.
  • +
+
+
+

2.2.1 (2006-05-22)

+
    +
  • Fixed occasional progress bar woes under Windows.
  • +
  • Fixed a bug in the registration system under Windows.
  • +
  • Nothing has been changed in the Mac OS X version, but I want to keep version in sync.
  • +
+
+
+

2.2.0 (2006-05-10)

+
    +
  • Added destination path re-creation options.
  • +
  • Added an ignore list.
  • +
  • Changed the main icon.
  • +
  • Improved dramatically the delta values feature.
  • +
+
+
+

2.1.2 (2006-04-18)

+
    +
  • Added the «Match similar words» option.
  • +
  • Fixed Power marking issues under Mac.
  • +
+
+
+

2.1.1 (2006-04-14)

+
    +
  • Added the «Display delta values» option.
  • +
  • Improved Power marking sorting speed under Mac.
  • +
  • Fixed Power marking sorting issues.
  • +
+
+
+

2.1.0 (2006-04-03)

+
    +
  • Added the Power Marker feature.
  • +
  • Fixed a column sorting bug. The results would sometimes lose their sort order.
  • +
  • Fixed a bug with the Make Reference feature. The results sometimes wasn’t correctly refreshed after the reference switch.
  • +
+
+
+

2.0.1 (2006-03-23)

+
    +
  • Fixed an issue occasionally occurring when trying to reload results from removable media that is no longer present.
  • +
+
+
+

2.0.0 (2006-03-17)

+
    +
  • Complete rewrite.
  • +
  • Now runs on Mac OS X.
  • +
+
+
+

1.0.0 (2004-09-24)

+
    +
  • Initial release.
  • +
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/uk/faq.html b/help/uk/faq.html new file mode 100644 index 00000000..3100bbd4 --- /dev/null +++ b/help/uk/faq.html @@ -0,0 +1,107 @@ + + + + + + + + Часті питання — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + + +
+ + +
+

Часті питання

+
+

Що таке dupeGuru?

+
+
+

Що робить його краще, ніж інші сканери дублювати?

+

Сканування є надзвичайно гнучкою. Ви можете налаштувати його, щоб дійсно отримати, яких результатів ви хочете. Ви можете прочитати більше про опція налаштування dupeGuru в Установки.

+
+
+

Наскільки безпечно використовувати dupeGuru?

+

Дуже безпечною. dupeGuru був розроблений, щоб переконатися, що ви не видаляєте файли, які ви не хотіли видалити. По-перше, існує система відліку папку, яка дозволяє визначити папки, в яких ви абсолютно не ** ** хочете dupeGuru, щоб ви видаляєте файли там, і тоді є система контрольної групи, що гарантує, що ви завжди ** * * тримати принаймні один член групи дублікатів.

+
+
+

Які обмеження демо dupeGuru?

+

У демо-режимі, ви можете тільки виконувати дії над 10 дублікати відразу. В +Fairware mode, однак, Є ніяких обмежень.

+
+
+

Знак коробку файл я хочу видалити відключена. Що я повинен зробити?

+

Ви не можете помітити посилання (перший файл) дублікат групи. Однак те, що ви можете зробити, полягає в сприянні дублювати файл довідки. Таким чином, якщо файл, який Ви хочете, щоб відзначити цю посилання, виділіть дублікатів файлів в групу, яку ви хочете просувати на посилання, і натисніть на кнопку Дії -> Додати вибраної посилання. Якщо посилання файл з папки посилання (назва файлу написані на синіми літерами), ви не можете видалити його з вихідного положення.

+
+
+

У мене є папка, з якої я справді не хочу, щоб видалити файли.

+

Якщо ви хочете бути впевнені, що dupeGuru ніколи не буде видаляти файл з певної папки, переконайтеся, що встановили в стан Посилання на: документ: Вибір папки.

+
+
+

Що це за „(X відкидається) «повідомлення в рядку стану?

+

У деяких випадках, кілька матчів не включені в остаточні результати з міркувань безпеки. Дозвольте мені навести приклад. У нас є 3 файли: A, B і C. Ми скануємо їх за допомогою фільтра низьких твердості. Сканер визначає, що матчі з B, матчі з С, але робить B ** не ** матч з С. При цьому, dupeGuru має вигляд проблеми. Вона не може створити дублікат групи А, В і С в це, тому що не всі файли в групі буде відповідати разом. Це може створити 2 групи: одна група AB, а потім одна група AC, але це не буде, з міркувань безпеки. Давайте думати про це: якщо Б не співпадає з С, вона, ймовірно, означає, що або B, C або обидва на самому ділі не дублікати. Якщо не було б 2 групи (АВ і АС), ви б у кінцевому підсумку видалити обидва B і C. І якщо один з них не дублювати, що насправді не те, що ви хочете робити, правильно? Так що dupeGuru робить у такому випадку є, щоб відмінити матч AC (і додає повідомлення в рядку стану). Таким чином, якщо ви вилучили B і повторно запустити сканування, вам доведеться відповідати змінного струму в наступний результат.

+
+
+

Я хочу, щоб відзначити всі файли з визначеної папки. Що я можу зробити?

+

Включити ошукані Тільки режим і натиснути на папку колонки для сортування дублікатів по папках. Потім він буде легким для вас, щоб вибрати всі дублікати з тієї ж папці, а потім натиснути клавішу пробіл, щоб відзначити всі вибрані дублікатів.

+
+
+

Я намагався відправити свої дублікати в корзину, але dupeGuru говорить мені, він не може це зробити. Чому? Що я можу зробити?

+

Більшу частину часу, тому dupeGuru не можете відправляти файли до кошика через права доступу до файлів. Ви повинні * написати * дозволу на файли, які ви хочете відправити у кошик. Якщо ви не знайомі з командним рядком, ви можете використовувати утиліти, такі як BatChmod виправити Ваші права.

+

Якщо dupeGuru ще дає вам неприємності після фіксації ваших прав, було кілька випадків, коли за допомогою «Переміщення Позначено до …» як обхідного шляху зробили свою справу. Таким чином, замість відправки файлів в корзину, ви посилаєте їх в тимчасову папку з «Переміщати Позначено до …» дії, а потім видалити цю тимчасову папку вручну.

+

Якщо все це не так, контакт УГ підтримки, ми зрозуміти це.

+
+
+

Доробити

+

This FAQ qestion is outdated, see english version.

+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/uk/folders.html b/help/uk/folders.html new file mode 100644 index 00000000..b228e882 --- /dev/null +++ b/help/uk/folders.html @@ -0,0 +1,83 @@ + + + + + + + + Вибір папки — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + + +
+ + +
+

Вибір папки

+

Перше вікно, ви бачите, коли ви запускаєте dupeGuru це вікно вибору папки. Це вікно містить список папок, які будуть скануватися при натисканні на Сканування.Це вікно досить проста у використанні. Якщо ви хочете додати папку, натисніть на кнопку +. Якщо ви додали папки перш, спливаюче меню зі списком останніх папки додав з’явиться. Ви можете натиснути на одну з них, щоб додати його прямо в свій список. Якщо натиснути на перший пункт меню, Додати новий папку …, вам буде запропоновано ввести папку додати. Якщо ви ніколи не додається папка, не з’явиться меню, і ви будете безпосередньо буде запропоновано ввести нову папку додати.

+

Альтернативний спосіб для додавання папок в список, щоб перетягнути їх в списку.

+

Щоб видалити папку, виберіть папку, видалити, і натисніть на -. Якщо папці вибирається при натисканні кнопки, обраної папки буде встановлений в виключені стану (див. нижче), а не видалений.

+
+

Папка держав

+

Кожна папка може знаходитися в одному з цих 3-х держав:

+
    +
  • ** Нормальний: ** дублікати знайдені в цю папку можна видалити.
  • +
  • ** Довідка: ** Дублікати знайти в цій папці не може бути видалені. Файли з цієї папки можна тільки в кінцевому підсумку в посилання позиція в групі обдурити. Якщо більш ніж один файл з папки посилання в кінцевому підсумку в тій же групі обдурити, тільки один, будуть збережені. Інші будуть видалені з групи.
  • +
  • ** Не включено: ** Файли в цьому каталозі не буде включений у перевірку.
  • +
+

Стан за замовчуванням до папки, звичайно, Нормальний. Ви можете використовувати Посилання стан для папки, якщо ви хочете бути впевнені, що ви не будете видаляти будь-які файли з нього.

+

Коли ви встановлюєте стан каталог, все підпапки цієї папки автоматично успадковує цей стан, якщо явно не включений стан підпапку в.

+
+

Доробити

+

Add iPhoto/Aperture/iTunes libraries notes

+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/uk/genindex.html b/help/uk/genindex.html new file mode 100644 index 00000000..4ff0892b --- /dev/null +++ b/help/uk/genindex.html @@ -0,0 +1,59 @@ + + + + + + + + + Індекс — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + +
+ + + +

Індекс

+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/uk/index.html b/help/uk/index.html new file mode 100644 index 00000000..62b8b703 --- /dev/null +++ b/help/uk/index.html @@ -0,0 +1,94 @@ + + + + + + + + dupeGuru help — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + +
+ + +
+

dupeGuru help

+

Хоча dupeGuru може бути легко використана без документації, читання цього файлу допоможе вам освоїти його. Якщо ви шукаєте керівництво для вашої першої дублювати сканування, ви можете поглянути на: Quick Start

+

Це гарна ідея, щоб зберегти dupeGuru оновлено. Ви можете завантажити останню версію на своєму homepage.

+

Contents:

+ +
+
+

Indices and tables

+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/help/uk/objects.inv b/help/uk/objects.inv new file mode 100644 index 00000000..d558bd70 --- /dev/null +++ b/help/uk/objects.inv @@ -0,0 +1,9 @@ +# Sphinx inventory version 2 +# Project: dupeGuru +# Version: 4.0.3 +# The remainder of this file is compressed using zlib. +xmQN0"2($n&Hb@Bb +6jE qvp{;?≐Ʉgyp$>r|*q_7s:8 +k_ +ޱq",K\ka&"@\΄kXZnk4E*N +UPȔMrU {X>J/{9xuHoȬ,Tؒ_h:x:]ʸĊ)(QQ] WŭY7DcIjS#mŠfٮ%MV<:Ȋ?R:o&[3[E˄pmYS7 9촗>oHf<> \ No newline at end of file diff --git a/help/uk/preferences.html b/help/uk/preferences.html new file mode 100644 index 00000000..1432bac9 --- /dev/null +++ b/help/uk/preferences.html @@ -0,0 +1,83 @@ + + + + + + + + Уподобання — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + + +
+ + +
+

Уподобання

+

Можна змішувати файл виду: Якщо ви встановите цей прапорець, дублювати групам дозволяється є файли з різними розширеннями. Якщо ви не перевірити його, ну, вони не є!

+

Ігнорувати дублікати hardlinking в той же файл: Якщо ця опція включена, dupeGuru перевірить дублікати, щоб побачити якщо вони посилаються на той самий індексний +дескриптор. Якщо вони це зроблять, вони не будуть вважатися дублікатами. (Тільки для OS X і Linux)

+

Використання регулярних виразів при фільтрації: Якщо ви відзначите цей прапорець, фільтрація розглядатиме ваш запит фільтра, як регулярний вираз. Пояснюючи їх виходить за рамки цього документа. Гарне місце для початку навчання він регулярного expressions.info.

+

Видалення порожніх папок після видалення або переміщення: Коли ця опція включена, папки будуть видалені через файл видалений або переміщений і папка порожня.

+

Копіювання і переміщення: Визначає, як операції копіювання та переміщення (в меню Дії) буде себе вести.

+
    +
  • Право на призначення: Всі файли будуть відправлені безпосередньо в пункт призначення, не намагаючись відтворити початковий шлях взагалі.
  • +
  • Повторно відносний шлях: шлях вихідний файл буде відтворений в папці призначення, аж до кореневого виділення в панелі Directories. Наприклад, якщо ви додали /Users/foobar/SomeFolder на панель Каталоги і переміщенні /Users/foobar/SomeFolder/SubFolder/SomeFile.ext до місця призначення /Users/foobar/MyDestination/SubFolder, кінцевим пунктом призначення для файлу буде /Users/foobar/MyDestination/SubFolder (SomeFolder були скорочені зі шляху джерела в кінцевий пункт призначення.).
  • +
  • ** Повторно абсолютний шлях: ** шлях вихідний файл буде відтворений в папці призначення в повному комплекті. Наприклад, якщо ви переміщаєте /Users/foobar/SomeFolder/SubFolder/SomeFile.ext до місця призначення /Users/foobar/MyDestination, кінцевим пунктом призначення для файлу буде /Users/foobar/MyDestination/Users/foobar/SomeFolder/SubFolder.
  • +
+

У всіх випадках, dupeGuru красиво ручки конфліктів імен шляхом додавання номера призначення ім’я файлу, якщо ім’я файлу вже існує в місці призначення.

+

Спеціальної команди: Це перевагу визначає команду, яка буде викликатися «Викликати спеціальної команди» дії. Ви можете посилатися ні на які зовнішні програми через цю дію. Це може бути корисно, якщо, наприклад, у вас є хороший додаток порівнюєте встановлені.

+

Формат команди такий же, як те, що ви повинні написати в командному рядку, за винятком того, що Є 2 заповнювачів: %d and %r. Ці наповнювачі будуть замінені на шлях вибраний обдурити (% г) і шлях до заслання на файл вибраного обдурити (%r).

+

Якщо шлях до виконуваного містить прогалини, необхідно укласти його в «» лапки. Ви також повинні докласти заповнювачів в лапки, бо це дуже можливо, що шлях до обдурених і посилання будуть містити пробіли. Ось приклад користувальницької команди:

+
"C:\Program Files\SuperDiffProg\SuperDiffProg.exe" "%d" "%r"
+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/uk/quick_start.html b/help/uk/quick_start.html new file mode 100644 index 00000000..c87d8893 --- /dev/null +++ b/help/uk/quick_start.html @@ -0,0 +1,76 @@ + + + + + + + + Швидкий старт — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + + +
+ + +
+

Швидкий старт

+

Щоб ви швидко почали з dupeGuru, давайте просто робити сканування за допомогою стандартних параметрів за замовчуванням.

+
    +
  • Запуск dupeGuru.
  • +
  • Додавання папок для сканування або перетягнути & краплі або кнопку «+».
  • +
  • Натисніть на сканування.
  • +
  • Почекайте, поки процес сканування завершено.
  • +
  • Подивіться на кожен дублікат (файли, які відступом) і переконайтеся, що це дійсно дублікат посиланням групи (файл вище дублювати без відступу та інвалідів вікна знак).
  • +
  • Якщо файл помилкових дублікатів, виділіть її та натисніть Дії -> Видалити вибрані з результатів.
  • +
  • Якщо ви впевнені, що немає помилкових дублікатів в результатах, натисніть на Редагувати -> Позначити Всі, а потім Дії -> Отправить Позначено до кошику.
  • +
+

Це тільки основні сканування. Є багато налаштування ви можете зробити, щоб отримати різні результати і кілька методів вивчення та зміни ваших результатів. Щоб дізнатися про них, щойно прочитав решту цього файлу довідки.

+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/uk/reprioritize.html b/help/uk/reprioritize.html new file mode 100644 index 00000000..105312d9 --- /dev/null +++ b/help/uk/reprioritize.html @@ -0,0 +1,84 @@ + + + + + + + + Повторне пріоритетів дублікатів — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + + +
+ + +
+

Повторне пріоритетів дублікатів

+

dupeGuru намагається автоматично визначити, які дублікат повинен відправитися в заслання кожної групи +позиції, але іноді це робиться неправильно. У багатьох випадках, розумний обдурити сортування з «Цінності Дельта» +і «ошукані Тільки» варіанти на додаток до «Зробити вибраної посилання» дія робить трюк, але +іноді, більш потужний варіант не потрібно. Тут зміни пріоритетів в діалог вступає в +грати. Ви можете викликати його через «змінити пріоритети Результати» пункт в меню «Дії».

+

Цей діалог дозволяє вам вибрати критерії, за якими посилання обдурити будуть відібрані в +кожній групі обдурити. Список доступних критеріїв зліва і перелік критеріїв ви +Обрана справа.

+

Критеріїв категорії слідують аргумент. Наприклад, «Розмір (Вищий)» означає, що обдурити +з великим розміром переможе. «Властивості папки (/Foo/Bar)» означає, що ошукані в цій папці буде перемогти. для додавання +критерій правом списку, спочатку виберіть категорію в спадному списку і виберіть +subargument в наведеному нижче списку, а потім натисніть на праву стрілку кнопки.

+

Порядок списку праворуч важливо (ви можете змінити порядок елементів через перетягнути і відпустити). коли +збір обдурити для довідки позицію, перший критерій використовується. Якщо є краватка, другий +критерій використовується і так далі і так далі. Наприклад, якщо ваші аргументи «Розмір (вищий)», а потім +«Файл (Не закінчується на номер)», заслання на файл, який буде обраний у групі буде +найбільших файл, а якщо два або декілька файлів мають однаковий розмір, який має ім’я файлу з +не закінчується номер буде використовуватися. Коли всі критерії привести до зв’язку, порядок, в якому ошукані +раніше були в групі буде використовуватися.

+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/uk/results.html b/help/uk/results.html new file mode 100644 index 00000000..7f76a481 --- /dev/null +++ b/help/uk/results.html @@ -0,0 +1,153 @@ + + + + + + + + Результати — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + + +
+ + +
+

Результати

+

Коли dupeGuru завершення сканування на наявність дублікатів, він покаже його результати у вигляді дубліката список групи.

+
+

Про дублікат групи

+

Дублікат група являє собою групу файлів, які весь матч разом. Кожна група має посиланням на файл і одного або більше однакових файлів. Посилання файл перший файл групи. Його марка вікно вимкнено. Під ним, і з відступом, які дублікатів файлів.

+

Ви можете відзначити дублікатів файлів, але ви ніколи не можете помітити посилання файл групи. Це захід безпеки, щоб запобігти dupeGuru від видалення не тільки повторювані файли, але їх посилання. Ти впевнений, що не хочу цього, чи не так?

+

Що визначає, які файли посилання і які файли є дублікатами спочатку свою папку держави. Файл з посиланням папка завжди буде посилання в дублікат групи. Якщо всі файли зі звичайної папки, розмір визначити, який файл буде ведення дублікат групи. dupeGuru припускає, що ви завжди хочете зберегти найбільших файл, так що великих файлів займе вихідне положення.

+

Ви можете змінити посилання файл групи вручну. Для цього виберіть дублікат файлу, який ви хочете просувати на посилання, і натисніть на кнопку Дії -> Додати вибраної посилання.

+
+
+

Перегляд результатів

+

Хоча ви можете просто натиснути на Правка -> Виділити все, а потім Дії -> Отправить Позначено до кошику швидко видалити всі дублікати файлів в результатах, завжди рекомендується переглянути всі дублікати перед видаляючи їх.

+

Щоб допомогти вам огляд результатів, ви можете викликати панель Докладніше. Ця панель показує всі деталі обраного файла, а також подробиці свого заслання в. Це дуже зручно, щоб швидко визначити, якщо дублікат дійсно дублікат. Ви також можете двічі клацнути по файлу, щоб відкрити його і пов’язані з ним програми.

+

Якщо у вас є більше помилкових дублікатів, ніж правда дублікатів (Якщо Ваш фільтр жорсткість дуже низька), кращий спосіб продовжити б переглянути дублікатів, знак істинного дублікати і натисніть Дії -> Отправить Позначено до кошику . Якщо у вас є більш вірно, ніж помилкових дублікатів дублікатів, замість цього можна позначити всі файли, які є помилковими дублікатів, а також використовувати Дії -> Видалити Помічені від результатів.

+
+
+

Маркування і вибір

+

Зазначені дублікат двох примірниках з невеликою прапорець поруч з ним, мають галочки. Обрано дублікат дубліката бути виділені. Кілька дій, вибір може бути виконана в dupeGuru стандартним чином (Shift/Command/Control клік). Ви можете перемикати знак стан всіх вибраних дублікати «, натиснувши просторі.

+
+
+

Показати тільки ошукані

+

Коли цей режим включений, дублікати відображаються без їх відповідного файлу довідки. Ви можете вибрати, марка і сортувати цей список, як і в звичайному режимі.

+

DupeGuru результати, коли в нормальному режимі, сортуються відповідно до дублікат групи „посиланням на файл. Це означає, що якщо ви хочете, наприклад, щоб відзначити все дублікати «EXE» розширенням, ви не можете просто сортувати результати по «Вид», щоб мати всі EXE дублікатів разом, тому що група може складатися з більш ніж одного типу файлів . Ось де обдурені Тільки режим вступає в гру. Щоб позначити всі ваші «EXE» дублікати, ви просто повинні:

+
    +
  • Включити ошукані Тільки режим.
  • +
  • Додати «Вид» колонку «Стовпці» меню.
  • +
  • Натисніть на те, що «Вид» колонки, щоб відсортувати список за типом.
  • +
  • Знайдена перша дублікат з «EXE» роду.
  • +
  • Виберіть його.
  • +
  • Перейдіть, щоб знайти останнього дубліката з «EXE» роду.
  • +
  • Утримуйте Shift і клацніть по ньому.
  • +
  • Натисніть Space, щоб позначити всі вибрані дублікатів.
  • +
+
+
+

Дельта значення

+

Якщо включити цей перемикач на деякі стовпці будуть відображати значення по відношенню до дубліката засланні, а не абсолютні значення. Ці дельти значення також будуть відображатися в різні кольори, щоб ви могли помітити їх легко. Наприклад, якщо дублікат 1,2 Мб і своє посилання в 1,4 Мб, розмір стовпець відображає -0,2 Мб.

+
+
+

Тільки ошукані і Дельта значення

+

Тільки ошукані режимі розкрити свою дійсну силу, коли ви використовуєте його з Delta Значення перемикач включений. Коли ви дозволите його, відносні значення буде відображатися замість абсолютних. Так що якщо, наприклад, ви хочете видалити з результатів всі дублікати, які є більш 300 Кб від їх посиланню, ви можете відсортувати дублікати тільки результати за розміром, виберіть всі дублікати при -300 в стовпці Розмір, видаляти їх, , а потім зробити те ж саме повторює більше 300 в нижній частині списку.

+

Ви можете також використовувати його для зміни посилання пріоритет повторювані список. Коли ви робите свіжі сканування, якщо Є немає посилання папки, заслання на файл кожної групи є найбільшою файл. Якщо ви хочете змінити, що, наприклад, в останній модифікації час, ви можете відсортувати дублікати тільки результати за часом модифікації в убування порядку , виберіть всі дублікати з часом зміни дельти значення більше 0 і натисніть Переконайтеся, обраної посилання. Причина, чому ви повинні зробити порядок сортування за спаданням, тому що якщо 2 файли серед таких же дублікат групи вибираються при натисканні на Зробити вибраної посилання, тільки перший із списку будуть зроблені посилання, інші будуть проігноровані . І так як ви хочете Остання зміна файлу для посилання, які мають порядок сортування за спаданням запевняє вас, що першим пунктом у списку буде останньої зміни.

+
+

Доробити

+

Add «Non-numerical delta» information.

+
+
+
+

Фільтрація

+

dupeGuru підтримує після сканування, фільтрації. З його допомогою ви можете звузити результати, щоб ви могли виконувати дії, на підмножини. Наприклад, ви можете легко помітити всі дублікати з їх ім’я файлу, що містить «копіювати» з результатів за допомогою фільтра.

+
+

Доробити

+

Qt has a toolbar search field now, not a menu item.

+
+

Windows: Для використання функції фільтрації, натисніть на Дії -> Застосувати фільтр, запишіть фільтр, який ви хочете застосувати і натисніть ОК. Щоб повернутися до нефільтроване результати, натисніть на Дії -> Скасувати фільтр.

+

Mac OS X: Для використання функції фільтрації, тип фільтра в «Фільтр» поле пошуку на панелі інструментів. Щоб повернутися до нефільтроване результаті, очистіть поле, або натисніть на кнопку «X».

+

У простому режимі (режим), що ви вводите в якості фільтра рядок, що використовується для виконання фактичної фільтрації, за винятком однієї маски: *. Таким чином, якщо ви введете «[*]» як ваш фільтр, він буде відповідати що-небудь з [] дужках в ньому, все, що між цими дужками.

+

Для більш просунутих фільтрів, ви можете включити «Використання регулярних виразів при фільтрації» на. Функція фільтрації буде використовувати регулярні вирази. Регулярний вираз мови для узгодження тексту. Пояснюючи їх виходить за рамки цього документа. Гарне місце для початку навчання він регулярного expressions.info.

+

Матчі не чутливі до регістру, в простих і регулярних виразів режимі.

+

Для фільтра, щоб відповідати, регулярний вираз не обов’язково має збігатися цілий файл, він просто зобов’язаний утримувати в ланцюжок, відповідну висловом.

+

Ви могли помітити, що не всі дублікати в результаті будуть відповідати вашим фільтром. Це тому, що як тільки одна копія в матчах групового фільтра, то вся група залишиться в результатах, таким чином Ви можете мати більш чітке уявлення про дубліката контексті. Тим не менш, не відповідні дублікати у «заслання режимі». Таким чином, можна виконувати дії, як Марк все і обов’язково тільки знак фільтрується дублікатів.

+
+
+

Дія меню

+
    +
  • Відкритий чорний список: Видаліть всі ігнорують матчі ви додали. Ви повинні почати новий пошук знову очищується список ігнорованих щоб бути ефективними.
  • +
  • Експорт результатів в XHTML: Візьміть поточні результати, а також створювати файл XHTML з нього. Стовпців, які видно при натисканні на цю кнопку буде стовпців у файлі XHTML. Файл автоматично відкриється в браузері за замовчуванням.
  • +
  • Надіслати Позначено в кошику: Відправити всі відмічені дублікати, сміття, це очевидно.
  • +
  • Видалити Помічені і заміна з Жорсткі: Передає всі відмічені дублікати, сміття, але після того, як зробили це, вилучені файли замінюються жорстких посилання до заслання на файл. (Тільки для OS X і Linux)
  • +
  • Переміщення Позначено в …: запросить призначення, а потім перемістити всі відмічені файли в тому, що призначення. Шлях вихідного файлу може бути відтворений в пункт призначення, залежно від «Копіювання і переміщення» переваги.
  • +
  • Скопіюйте Позначено в …: запитає у вас місце, а потім скопіювати всі вибрані файли до цього пункту призначення. Шлях вихідного файлу може бути відтворений в пункт призначення, залежно від «Копіювання і переміщення» переваги.
  • +
  • Видалити Помічені з результатів: Видалити все відмічені дублікатів з результату пошуку. Самі файли не будуть порушені й залишаться, де вони.
  • +
  • Видалити вибрані з результатів: Видалити всі вибрані дублікатів з результату пошуку. Зверніть увагу, що всі вибрані файли посилання будуть ігноруватися, тільки дублікати можуть бути видалені з цією дією.
  • +
  • Зробити Обраний Довідка: Сприяння всі вибрані дублікатів посилання. Якщо дублікат частиною групи, що має посиланням на файл найближчі із заслання папки (в синій колір), не будуть прийняті заходи для цього дублікат. Якщо більш ніж один дублікат серед тієї ж групи обрані, тільки перший з кожної групи буде заохочуватися.
  • +
  • Додати обрані в чорний список: Це спочатку видаляє всі вибрані дублікати з результатів, а потім додати матчу, які дублюють та опорний струм в чорний список. Цей матч не прийде знову в подальшої перевірки. Копіювати себе і, можливо, повернеться, але він буде шукатися в іншій посиланням на файл. Ви можете очистити список ігнорованих з Відкритий чорний список команди.
  • +
  • Відкрите Обраний з додатків за замовчунням: Відкрийте файл за допомогою програми, пов’язаного з типом обраного файлу.
  • +
  • Розкривати Обраний в Finder: Відкрийте папку, яка містить вибраний файл.
  • +
  • Викликати спеціальної команди: Викликає зовнішню програму ви встановили в настройках з використанням виділеного фрагмента в якості аргументів у виклику.
  • +
  • Перейменування обрано: Запит нове ім’я, а потім перейменувати вибраний файл.
  • +
+
+

Доробити

+

Add Move and iPhoto/iTunes warning

+
+
+

Доробити

+

Add «Deletion Options» section.

+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/help/uk/search.html b/help/uk/search.html new file mode 100644 index 00000000..b5930303 --- /dev/null +++ b/help/uk/search.html @@ -0,0 +1,83 @@ + + + + + + + + Пошук — dupeGuru 4.0.3 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +

Пошук

+
+ +

+ Будь-ласка вімкніть підтримку JavaScript, щоб ввікнути +" +" пошук. +

+
+

+ Звідси ви можете шукати ці документи. Введіть ваші пошукові + слова в поле нижче та натисніть "пошук". Зауважте що функція + пошуку автоматично шукатиме за всіма словами. Сторінки + що містять менше слів не з'являться в результуючому списку. +

+
+ + + +
+ +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/help/uk/searchindex.js b/help/uk/searchindex.js new file mode 100644 index 00000000..106a7347 --- /dev/null +++ b/help/uk/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["changelog","faq","folders","index","preferences","quick_start","reprioritize","results"],envversion:53,filenames:["changelog.rst","faq.rst","folders.rst","index.rst","preferences.rst","quick_start.rst","reprioritize.rst","results.rst"],objects:{},objnames:{},objtypes:{},terms:{"32bit":0,"64bit":0,"\u0430":[1,2,5,6,7],"\u0430\u0431\u043e":[1,4,5,6,7],"\u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u0438\u0439":4,"\u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u0438\u0445":7,"\u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e":1,"\u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u0456":7,"\u0430\u0432":1,"\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e":[2,6,7],"\u0430\u0436":4,"\u0430\u043b\u0435":[6,7],"\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u0438\u0439":2,"\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442":6,"\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0438":6,"\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0456\u0432":7,"\u0430\u0441":1,"\u0431":[1,7],"\u0431\u0430\u0433\u0430\u0442\u043e":5,"\u0431\u0430\u0433\u0430\u0442\u044c\u043e\u0445":6,"\u0431\u0430\u0447\u0438\u0442\u0435":2,"\u0431\u0435\u0437":[3,5,7],"\u0431\u0435\u0437\u043f\u0435\u043a\u0438":[1,7],"\u0431\u0435\u0437\u043f\u0435\u0447\u043d\u043e\u044e":1,"\u0431\u0435\u0437\u043f\u043e\u0441\u0435\u0440\u0435\u0434\u043d\u044c\u043e":[2,4],"\u0431\u043e":4,"\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0456":7,"\u0431\u0443\u0432":1,"\u0431\u0443\u0434\u0435":[1,2,4,6,7],"\u0431\u0443\u0434\u0435\u0442\u0435":2,"\u0431\u0443\u0434\u0443\u0442\u044c":[2,4,6,7],"\u0431\u0443\u0434\u044c":2,"\u0431\u0443\u043b\u0438":[4,6],"\u0431\u0443\u043b\u043e":1,"\u0431\u0443\u0442\u0438":[1,2,3,4,7],"\u0431\u0456\u043b\u044c\u0448":[2,6,7],"\u0431\u0456\u043b\u044c\u0448\u0435":[1,7],"\u0431\u0456\u043b\u044c\u0448\u0443":1,"\u0432":[2,4,5,6,7],"\u0432\u0430\u0436\u043b\u0438\u0432\u043e":6,"\u0432\u0430\u043c":[1,2,3,6,7],"\u0432\u0430\u0440\u0456\u0430\u043d\u0442":6,"\u0432\u0430\u0440\u0456\u0430\u043d\u0442\u0438":6,"\u0432\u0430\u0441":[1,4,7],"\u0432\u0430\u0448":[4,7],"\u0432\u0430\u0448\u0438\u043c":7,"\u0432\u0430\u0448\u0438\u0445":[1,5],"\u0432\u0430\u0448\u043e\u0457":3,"\u0432\u0430\u0448\u0456":[1,6,7],"\u0432\u0432\u0430\u0436\u0430\u0442\u0438\u0441\u044f":4,"\u0432\u0432\u0435\u0434\u0435\u0442\u0435":7,"\u0432\u0432\u0435\u0441\u0442\u0438":2,"\u0432\u0432\u043e\u0434\u0438\u0442\u0435":7,"\u0432\u0435\u0434\u0435\u043d\u043d\u044f":7,"\u0432\u0435\u043b\u0438\u043a\u0438\u043c":6,"\u0432\u0435\u043b\u0438\u043a\u0438\u0445":7,"\u0432\u0435\u0440\u0441\u0456\u044e":3,"\u0432\u0435\u0441\u0442\u0438":4,"\u0432\u0435\u0441\u044c":7,"\u0432\u0436\u0435":4,"\u0432\u0437\u0430\u0433\u0430\u043b\u0456":4,"\u0432\u0438":[1,2,3,4,5,6,7],"\u0432\u0438\u0431\u0435\u0440\u0456\u0442\u044c":[2,6,7],"\u0432\u0438\u0431\u0438\u0440\u0430\u044e\u0442\u044c\u0441\u044f":7,"\u0432\u0438\u0431\u0438\u0440\u0430\u0454\u0442\u044c\u0441\u044f":2,"\u0432\u0438\u0431\u043e\u0440\u0443":2,"\u0432\u0438\u0431\u0440\u0430\u043d\u0438\u0439":[4,7],"\u0432\u0438\u0431\u0440\u0430\u043d\u0438\u0445":7,"\u0432\u0438\u0431\u0440\u0430\u043d\u043e\u0433\u043e":4,"\u0432\u0438\u0431\u0440\u0430\u043d\u043e\u0457":[1,6,7],"\u0432\u0438\u0431\u0440\u0430\u043d\u0456":[1,5,7],"\u0432\u0438\u0431\u0440\u0430\u0442\u0438":[1,6,7],"\u0432\u0438\u0431\u0456\u0440":[1,3],"\u0432\u0438\u0432\u0447\u0435\u043d\u043d\u044f":5,"\u0432\u0438\u0433\u043b\u044f\u0434":1,"\u0432\u0438\u0433\u043b\u044f\u0434\u0456":7,"\u0432\u0438\u0434":7,"\u0432\u0438\u0434\u0430\u043b\u0435\u043d\u0438\u0439":[2,4],"\u0432\u0438\u0434\u0430\u043b\u0435\u043d\u043d\u044f":[4,7],"\u0432\u0438\u0434\u0430\u043b\u0435\u043d\u0456":[2,4,7],"\u0432\u0438\u0434\u0430\u043b\u0438\u0442\u0438":[2,5,7],"\u0432\u0438\u0434\u0430\u043b\u044f\u0442\u0438":[1,2,7],"\u0432\u0438\u0434\u0430\u043b\u044f\u044e\u0447\u0438":7,"\u0432\u0438\u0434\u0430\u043b\u044f\u0454":7,"\u0432\u0438\u0434\u0430\u043b\u044f\u0454\u0442\u0435":1,"\u0432\u0438\u0434\u0430\u043b\u0456\u0442\u044c":7,"\u0432\u0438\u0434\u043d\u043e":7,"\u0432\u0438\u0434\u0443":4,"\u0432\u0438\u0434\u0456\u043b\u0435\u043d\u043d\u044f":4,"\u0432\u0438\u0434\u0456\u043b\u0435\u043d\u043e\u0433\u043e":7,"\u0432\u0438\u0434\u0456\u043b\u0435\u043d\u0456":7,"\u0432\u0438\u0434\u0456\u043b\u0438\u0442\u0438":7,"\u0432\u0438\u0434\u0456\u043b\u0456\u0442\u044c":[1,5],"\u0432\u0438\u0437\u043d\u0430\u0447\u0430\u0454":[1,4,7],"\u0432\u0438\u0437\u043d\u0430\u0447\u0438\u0442\u0438":[1,6,7],"\u0432\u0438\u043a\u043b\u0438\u043a\u0430\u0442\u0438":[4,6,7],"\u0432\u0438\u043a\u043b\u0438\u043a\u0430\u0442\u0438\u0441\u044f":4,"\u0432\u0438\u043a\u043b\u0438\u043a\u0430\u0454":7,"\u0432\u0438\u043a\u043b\u0438\u043a\u0443":7,"\u0432\u0438\u043a\u043b\u044e\u0447\u0435\u043d\u0456":2,"\u0432\u0438\u043a\u043e\u043d\u0430\u043d\u0430":7,"\u0432\u0438\u043a\u043e\u043d\u0430\u043d\u043d\u044f":7,"\u0432\u0438\u043a\u043e\u043d\u0443\u0432\u0430\u043d\u043e\u0433\u043e":4,"\u0432\u0438\u043a\u043e\u043d\u0443\u0432\u0430\u0442\u0438":[1,7],"\u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u0430\u043d\u0430":3,"\u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u0430\u043d\u043d\u044f":[4,7],"\u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u0430\u043d\u043d\u044f\u043c":7,"\u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u0430\u043d\u043d\u0456":2,"\u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0432\u0430\u0442\u0438":[2,7],"\u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0432\u0430\u0442\u0438\u0441\u044f":6,"\u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0454\u0442\u0435":7,"\u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0454\u0442\u044c\u0441\u044f":[6,7],"\u0432\u0438\u043b\u0443\u0447\u0435\u043d\u0456":7,"\u0432\u0438\u043b\u0443\u0447\u0438\u043b\u0438":1,"\u0432\u0438\u043c\u043a\u043d\u0435\u043d\u043e":7,"\u0432\u0438\u043d\u044f\u0442\u043a\u043e\u043c":[4,7],"\u0432\u0438\u043f\u0430\u0434\u043a\u0430\u0445":[1,4,6],"\u0432\u0438\u043f\u0430\u0434\u043a\u0443":1,"\u0432\u0438\u043f\u0430\u0434\u043a\u0456\u0432":1,"\u0432\u0438\u043f\u0440\u0430\u0432\u0438\u0442\u0438":1,"\u0432\u0438\u0440\u0430\u0437":[4,7],"\u0432\u0438\u0440\u0430\u0437\u0438":7,"\u0432\u0438\u0440\u0430\u0437\u0456\u0432":[4,7],"\u0432\u0438\u0441\u043b\u043e\u0432\u043e\u043c":7,"\u0432\u0438\u0445\u043e\u0434\u0438\u0442\u044c":[4,7],"\u0432\u0438\u0445\u0456\u0434\u043d\u0435":7,"\u0432\u0438\u0445\u0456\u0434\u043d\u0438\u0439":4,"\u0432\u0438\u0445\u0456\u0434\u043d\u043e\u0433\u043e":[1,7],"\u0432\u0438\u0449\u0435":5,"\u0432\u0438\u0449\u0438\u0439":6,"\u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0430":4,"\u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439":[2,7],"\u0432\u043a\u043b\u044e\u0447\u0435\u043d\u043e":2,"\u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0456":1,"\u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0438":[1,7],"\u0432\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456":6,"\u0432\u043e\u043d\u0430":1,"\u0432\u043e\u043d\u0438":[4,7],"\u0432\u043f\u0435\u0432\u043d\u0435\u043d\u0438\u0439":7,"\u0432\u043f\u0435\u0432\u043d\u0435\u043d\u0456":[1,2,5],"\u0432\u0440\u0443\u0447\u043d\u0443":[1,7],"\u0432\u0441\u0435":[1,2,7],"\u0432\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438":[1,7],"\u0432\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435":4,"\u0432\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439":2,"\u0432\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0456":4,"\u0432\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u044e\u0454\u0442\u0435":2,"\u0432\u0441\u0442\u0443\u043f\u0430\u0454":[6,7],"\u0432\u0441\u044f":7,"\u0432\u0441\u0456":[4,5,6,7],"\u0432\u0441\u0456\u0445":[4,7],"\u0432\u0456\u0434":7,"\u0432\u0456\u0434\u0437\u043d\u0430\u0447\u0438\u0442\u0435":4,"\u0432\u0456\u0434\u0437\u043d\u0430\u0447\u0438\u0442\u0438":7,"\u0432\u0456\u0434\u043a\u0440\u0438\u0439\u0442\u0435":7,"\u0432\u0456\u0434\u043a\u0440\u0438\u0442\u0435":7,"\u0432\u0456\u0434\u043a\u0440\u0438\u0442\u0438":7,"\u0432\u0456\u0434\u043a\u0440\u0438\u0442\u0438\u0439":7,"\u0432\u0456\u0434\u043a\u0440\u0438\u0454\u0442\u044c\u0441\u044f":7,"\u0432\u0456\u0434\u043b\u0456\u043a\u0443":1,"\u0432\u0456\u0434\u043c\u0456\u043d\u0438\u0442\u0438":1,"\u0432\u0456\u0434\u043c\u0456\u0447\u0435\u043d\u0456":7,"\u0432\u0456\u0434\u043d\u043e\u0441\u043d\u0438\u0439":4,"\u0432\u0456\u0434\u043d\u043e\u0441\u043d\u0456":7,"\u0432\u0456\u0434\u043d\u043e\u0448\u0435\u043d\u043d\u044e":7,"\u0432\u0456\u0434\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u0438":7,"\u0432\u0456\u0434\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u0438\u0441\u044f":7,"\u0432\u0456\u0434\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u044c\u0441\u044f":7,"\u0432\u0456\u0434\u043e\u0431\u0440\u0430\u0436\u0430\u0454":7,"\u0432\u0456\u0434\u043f\u043e\u0432\u0456\u0434\u0430\u0442\u0438":[1,7],"\u0432\u0456\u0434\u043f\u043e\u0432\u0456\u0434\u043d\u043e":7,"\u0432\u0456\u0434\u043f\u043e\u0432\u0456\u0434\u043d\u043e\u0433\u043e":7,"\u0432\u0456\u0434\u043f\u043e\u0432\u0456\u0434\u043d\u0443":7,"\u0432\u0456\u0434\u043f\u043e\u0432\u0456\u0434\u043d\u0456":7,"\u0432\u0456\u0434\u043f\u0440\u0430\u0432\u0438\u0442\u0438":7,"\u0432\u0456\u0434\u043f\u0440\u0430\u0432\u0438\u0442\u0438\u0441\u044f":6,"\u0432\u0456\u0434\u043f\u0440\u0430\u0432\u043a\u0438":1,"\u0432\u0456\u0434\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0456":4,"\u0432\u0456\u0434\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u0438":1,"\u0432\u0456\u0434\u043f\u0443\u0441\u0442\u0438\u0442\u0438":6,"\u0432\u0456\u0434\u0440\u0430\u0437\u0443":1,"\u0432\u0456\u0434\u0441\u043e\u0440\u0442\u0443\u0432\u0430\u0442\u0438":7,"\u0432\u0456\u0434\u0441\u0442\u0443\u043f\u043e\u043c":[5,7],"\u0432\u0456\u0434\u0441\u0442\u0443\u043f\u0443":5,"\u0432\u0456\u0434\u0442\u0432\u043e\u0440\u0435\u043d\u0438\u0439":[4,7],"\u0432\u0456\u0434\u0442\u0432\u043e\u0440\u0438\u0442\u0438":4,"\u0432\u0456\u0434\u0456\u0431\u0440\u0430\u043d\u0456":6,"\u0432\u0456\u0437\u044c\u043c\u0456\u0442\u044c":7,"\u0432\u0456\u043a\u043d\u0430":5,"\u0432\u0456\u043a\u043d\u043e":[2,7],"\u0432\u0456\u043d":[4,7],"\u0432\u0456\u0440\u043d\u043e":7,"\u0433":4,"\u0433\u0430\u043b\u043e\u0447\u043a\u0438":7,"\u0433\u0430\u0440\u0430\u043d\u0442\u0443\u0454":1,"\u0433\u0430\u0440\u043d\u0430":3,"\u0433\u0430\u0440\u043d\u0435":[4,7],"\u0433\u043d\u0443\u0447\u043a\u043e\u044e":1,"\u0433\u0440\u0430\u0442\u0438":6,"\u0433\u0440\u0443":7,"\u0433\u0440\u0443\u043f\u0430":[1,7],"\u0433\u0440\u0443\u043f\u0430\u043c":4,"\u0433\u0440\u0443\u043f\u0438":[1,2,3,5,6],"\u0433\u0440\u0443\u043f\u043e\u0432\u043e\u0433\u043e":7,"\u0433\u0440\u0443\u043f\u0443":[1,7],"\u0433\u0440\u0443\u043f\u0456":[1,2,6],"\u0434\u0430\u0432\u0430\u0439\u0442\u0435":[1,5],"\u0434\u0430\u043b\u0456":6,"\u0434\u0430\u0454":1,"\u0434\u0432\u0430":6,"\u0434\u0432\u043e\u0445":7,"\u0434\u0432\u0456\u0447\u0456":7,"\u0434\u0435":7,"\u0434\u0435\u043a\u0456\u043b\u044c\u043a\u0430":6,"\u0434\u0435\u043b\u044c\u0442\u0430":[3,6],"\u0434\u0435\u043b\u044c\u0442\u0438":7,"\u0434\u0435\u0440\u0436\u0430\u0432":3,"\u0434\u0435\u0440\u0436\u0430\u0432\u0438":7,"\u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440":4,"\u0434\u0435\u0442\u0430\u043b\u0456":7,"\u0434\u0435\u044f\u043a\u0438\u0445":1,"\u0434\u0435\u044f\u043a\u0456":7,"\u0434\u0436\u0435\u0440\u0435\u043b\u0430":4,"\u0434\u0438\u0432":2,"\u0434\u043b\u044f":[1,2,3,4,5,6,7],"\u0434\u043e":[1,2,4,5,6,7],"\u0434\u043e\u0432\u0435\u0434\u0435\u0442\u044c\u0441\u044f":1,"\u0434\u043e\u0432\u0456\u0434\u043a\u0430":[2,7],"\u0434\u043e\u0432\u0456\u0434\u043a\u0438":[1,5,6,7],"\u0434\u043e\u0434\u0430\u0432":2,"\u0434\u043e\u0434\u0430\u0432\u0430\u043d\u043d\u044f":[2,4,5,6],"\u0434\u043e\u0434\u0430\u043b\u0438":[2,4,7],"\u0434\u043e\u0434\u0430\u0442\u0438":[1,2,7],"\u0434\u043e\u0434\u0430\u0442\u043a\u0456\u0432":7,"\u0434\u043e\u0434\u0430\u0442\u043e\u043a":[4,6],"\u0434\u043e\u0434\u0430\u0454":1,"\u0434\u043e\u0434\u0430\u0454\u0442\u044c\u0441\u044f":2,"\u0434\u043e\u0437\u0432\u043e\u043b\u0438\u0442\u0435":7,"\u0434\u043e\u0437\u0432\u043e\u043b\u0443":1,"\u0434\u043e\u0437\u0432\u043e\u043b\u044c\u0442\u0435":1,"\u0434\u043e\u0437\u0432\u043e\u043b\u044f\u0454":[1,6],"\u0434\u043e\u0437\u0432\u043e\u043b\u044f\u0454\u0442\u044c\u0441\u044f":4,"\u0434\u043e\u043a\u043b\u0430\u0434\u043d\u0456\u0448\u0435":7,"\u0434\u043e\u043a\u043b\u0430\u0441\u0442\u0438":4,"\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442":1,"\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430":[4,7],"\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0456\u0457":3,"\u0434\u043e\u043f\u043e\u043c\u043e\u0433\u043e\u044e":[1,5,7],"\u0434\u043e\u043f\u043e\u043c\u043e\u0433\u0442\u0438":7,"\u0434\u043e\u043f\u043e\u043c\u043e\u0436\u0435":3,"\u0434\u043e\u0441\u0438\u0442\u044c":2,"\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0438\u0445":6,"\u0434\u043e\u0441\u0442\u0443\u043f\u0443":1,"\u0434\u0440\u0443\u0433\u0438\u0439":6,"\u0434\u0443\u0431\u043b\u044e\u0432\u0430\u0442\u0438":[3,4,5],"\u0434\u0443\u0431\u043b\u044e\u044e\u0442\u044c":7,"\u0434\u0443\u0431\u043b\u0456\u043a\u0430\u0442":[1,3,5,6],"\u0434\u0443\u0431\u043b\u0456\u043a\u0430\u0442\u0430":7,"\u0434\u0443\u0431\u043b\u0456\u043a\u0430\u0442\u0430\u043c\u0438":[4,7],"\u0434\u0443\u0431\u043b\u0456\u043a\u0430\u0442\u0438":[2,4,7],"\u0434\u0443\u0431\u043b\u0456\u043a\u0430\u0442\u0456\u0432":[1,3,5,7],"\u0434\u0443\u0436\u0435":[1,4,7],"\u0434\u0443\u0436\u043a\u0430\u043c\u0438":7,"\u0434\u0443\u0436\u043a\u0430\u0445":7,"\u0434\u0443\u043c\u0430\u0442\u0438":1,"\u0434\u0456\u0430\u043b\u043e\u0433":6,"\u0434\u0456\u0437\u043d\u0430\u0442\u0438\u0441\u044f":5,"\u0434\u0456\u0439":7,"\u0434\u0456\u0439\u0441\u043d\u043e":[1,5,7],"\u0434\u0456\u0439\u0441\u043d\u0443":7,"\u0434\u0456\u043b\u0456":1,"\u0434\u0456\u044e":4,"\u0434\u0456\u044f":[3,6],"\u0434\u0456\u0454\u044e":7,"\u0434\u0456\u0457":[1,4,5,6,7],"\u0435\u043a\u0441\u043f\u043e\u0440\u0442":7,"\u0435\u043b\u0435\u043c\u0435\u043d\u0442\u0456\u0432":6,"\u0435\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0438\u043c\u0438":7,"\u0436":[1,7],"\u0436\u0435":[2,4,7],"\u0436\u043e\u0440\u0441\u0442\u043a\u0438\u0445":7,"\u0436\u043e\u0440\u0441\u0442\u043a\u0456":7,"\u0436\u043e\u0440\u0441\u0442\u043a\u0456\u0441\u0442\u044c":7,"\u0437":[2,4,5,6,7],"\u0437\u0430":[2,4,5,6,7],"\u0437\u0430\u0432\u0430\u043d\u0442\u0430\u0436\u0438\u0442\u0438":3,"\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044f":7,"\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043e":5,"\u0437\u0430\u0432\u0436\u0434\u0438":[1,7],"\u0437\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0456":7,"\u0437\u0430\u0439\u043c\u0435":7,"\u0437\u0430\u043a\u0456\u043d\u0447\u0443\u0454\u0442\u044c\u0441\u044f":6,"\u0437\u0430\u043b\u0435\u0436\u043d\u043e":7,"\u0437\u0430\u043b\u0438\u0448\u0430\u0442\u044c\u0441\u044f":7,"\u0437\u0430\u043b\u0438\u0448\u0438\u0442\u044c\u0441\u044f":7,"\u0437\u0430\u043c\u043e\u0432\u0447\u0443\u0432\u0430\u043d\u043d\u044f\u043c":[2,5,7],"\u0437\u0430\u043c\u043e\u0432\u0447\u0443\u043d\u043d\u044f\u043c":7,"\u0437\u0430\u043c\u0456\u043d\u0430":7,"\u0437\u0430\u043c\u0456\u043d\u0435\u043d\u0456":4,"\u0437\u0430\u043c\u0456\u043d\u044e\u044e\u0442\u044c\u0441\u044f":7,"\u0437\u0430\u043c\u0456\u0441\u0442\u044c":[1,7],"\u0437\u0430\u043e\u0445\u043e\u0447\u0443\u0432\u0430\u0442\u0438\u0441\u044f":7,"\u0437\u0430\u043f\u0435\u0432\u043d\u044f\u0454":7,"\u0437\u0430\u043f\u0438\u0442":[4,7],"\u0437\u0430\u043f\u0438\u0442\u0430\u0454":7,"\u0437\u0430\u043f\u0438\u0448\u0456\u0442\u044c":7,"\u0437\u0430\u043f\u043e\u0431\u0456\u0433\u0442\u0438":7,"\u0437\u0430\u043f\u043e\u0432\u043d\u044e\u0432\u0430\u0447\u0456\u0432":4,"\u0437\u0430\u043f\u0440\u043e\u043f\u043e\u043d\u043e\u0432\u0430\u043d\u043e":2,"\u0437\u0430\u043f\u0440\u043e\u0441\u0438\u0442\u044c":7,"\u0437\u0430\u043f\u0443\u0441\u043a":5,"\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0454\u0442\u0435":2,"\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0438":1,"\u0437\u0430\u0441\u043b\u0430\u043d\u043d\u044f":[4,6,7],"\u0437\u0430\u0441\u043b\u0430\u043d\u043d\u0456":7,"\u0437\u0430\u0441\u0442\u043e\u0441\u0443\u0432\u0430\u0442\u0438":7,"\u0437\u0430\u0445\u043e\u0434\u0438":7,"\u0437\u0430\u0445\u0456\u0434":7,"\u0437\u0431\u0435\u0440\u0435\u0433\u0442\u0438":[3,7],"\u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043d\u0456":2,"\u0437\u0431\u0456\u0433\u0430\u0442\u0438\u0441\u044f":7,"\u0437\u0431\u0456\u0440":6,"\u0437\u0432":6,"\u0437\u0432\u0435\u0440\u043d\u0456\u0442\u044c":7,"\u0437\u0432\u0438\u0447\u0430\u0439\u043d\u043e":2,"\u0437\u0432\u0438\u0447\u0430\u0439\u043d\u043e\u043c\u0443":7,"\u0437\u0432\u0438\u0447\u0430\u0439\u043d\u043e\u0457":7,"\u0437\u0432\u0443\u0437\u0438\u0442\u0438":7,"\u0437\u043b\u0456\u0432\u0430":6,"\u0437\u043c\u0456\u043d\u0430":7,"\u0437\u043c\u0456\u043d\u0438":[5,6,7],"\u0437\u043c\u0456\u043d\u0438\u0442\u0438":[6,7],"\u0437\u043c\u0456\u043d\u043d\u043e\u0433\u043e":1,"\u0437\u043c\u0456\u0448\u0443\u0432\u0430\u0442\u0438":4,"\u0437\u043d\u0430\u0439\u0434\u0435\u043d\u0430":7,"\u0437\u043d\u0430\u0439\u0434\u0435\u043d\u0456":2,"\u0437\u043d\u0430\u0439\u043e\u043c\u0456":1,"\u0437\u043d\u0430\u0439\u0442\u0438":[2,7],"\u0437\u043d\u0430\u043a":[5,7],"\u0437\u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0438\u0441\u044f":2,"\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044f":3,"\u0437\u043d\u043e\u0432\u0443":7,"\u0437\u043e\u0431\u043e\u0432":7,"\u0437\u043e\u0432\u043d\u0456\u0448\u043d\u044e":7,"\u0437\u043e\u0432\u043d\u0456\u0448\u043d\u0456":4,"\u0437\u0440\u043e\u0431\u0438\u043b\u0438":[1,7],"\u0437\u0440\u043e\u0431\u0438\u0442\u0438":[5,6,7],"\u0437\u0440\u043e\u0431\u043b\u0435\u043d\u0456":7,"\u0437\u0440\u043e\u0431\u043b\u044f\u0442\u044c":4,"\u0437\u0440\u043e\u0437\u0443\u043c\u0456\u0442\u0438":1,"\u0437\u0440\u0443\u0447\u043d\u043e":7,"\u0437\u0456":[2,4,7],"\u0439":7,"\u0439\u043c\u043e\u0432\u0456\u0440\u043d\u043e":1,"\u0439\u043e\u0433\u043e":[2,3,4,6,7],"\u043a\u0430\u0442\u0430\u043b\u043e\u0433":2,"\u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0438":4,"\u043a\u0430\u0442\u0430\u043b\u043e\u0437\u0456":2,"\u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0456\u044e":6,"\u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0456\u0457":6,"\u043a\u0431":7,"\u043a\u0435\u0440\u0456\u0432\u043d\u0438\u0446\u0442\u0432\u043e":3,"\u043a\u043b\u0430\u0432\u0456\u0448\u0443":1,"\u043a\u043b\u0430\u0446\u043d\u0443\u0442\u0438":7,"\u043a\u043b\u0430\u0446\u043d\u0456\u0442\u044c":7,"\u043a\u043b\u0456\u043a":7,"\u043a\u043d\u043e\u043f\u043a\u0438":[2,6],"\u043a\u043d\u043e\u043f\u043a\u0443":[1,2,5,7],"\u043a\u043e\u0436\u0435\u043d":5,"\u043a\u043e\u0436\u043d\u0430":[2,7],"\u043a\u043e\u0436\u043d\u043e\u0457":[6,7],"\u043a\u043e\u0436\u043d\u0456\u0439":6,"\u043a\u043e\u043b\u0438":[1,2,4,6,7],"\u043a\u043e\u043b\u043e\u043d\u043a\u0438":[1,7],"\u043a\u043e\u043b\u043e\u043d\u043a\u0443":7,"\u043a\u043e\u043b\u044c\u043e\u0440\u0438":7,"\u043a\u043e\u043b\u0456\u0440":7,"\u043a\u043e\u043c\u0430\u043d\u0434\u0438":[4,7],"\u043a\u043e\u043c\u0430\u043d\u0434\u043d\u0438\u043c":1,"\u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u043c\u0443":4,"\u043a\u043e\u043c\u0430\u043d\u0434\u0443":4,"\u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0442\u0456":4,"\u043a\u043e\u043d\u0442\u0430\u043a\u0442":1,"\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0456":7,"\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c\u043d\u043e\u0457":1,"\u043a\u043e\u043d\u0444\u043b\u0456\u043a\u0442\u0456\u0432":4,"\u043a\u043e\u043f\u0456\u044e\u0432\u0430\u043d\u043d\u044f":[4,7],"\u043a\u043e\u043f\u0456\u044e\u0432\u0430\u0442\u0438":7,"\u043a\u043e\u043f\u0456\u044f":7,"\u043a\u043e\u0440\u0435\u043d\u0435\u0432\u043e\u0433\u043e":4,"\u043a\u043e\u0440\u0438\u0441\u043d\u043e":4,"\u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u043b\u044c\u043d\u0438\u0446\u044c\u043a\u043e\u0457":4,"\u043a\u043e\u0448\u0438\u043a":1,"\u043a\u043e\u0448\u0438\u043a\u0430":1,"\u043a\u043e\u0448\u0438\u043a\u0443":[5,7],"\u043a\u0440\u0430\u0432\u0430\u0442\u043a\u0430":6,"\u043a\u0440\u0430\u043f\u043b\u0456":5,"\u043a\u0440\u0430\u0441\u0438\u0432\u043e":4,"\u043a\u0440\u0430\u0449\u0438\u0439":7,"\u043a\u0440\u0438\u0442\u0435\u0440\u0456\u0439":6,"\u043a\u0440\u0438\u0442\u0435\u0440\u0456\u0457":6,"\u043a\u0440\u0438\u0442\u0435\u0440\u0456\u0457\u0432":6,"\u043a\u0456\u043b\u044c\u043a\u0430":[1,5,7],"\u043a\u0456\u043d\u0446\u0435\u0432\u0438\u0439":4,"\u043a\u0456\u043d\u0446\u0435\u0432\u0438\u043c":4,"\u043a\u0456\u043d\u0446\u0435\u0432\u043e\u043c\u0443":[1,2],"\u043b\u0430\u043d\u0446\u044e\u0436\u043e\u043a":7,"\u043b\u0430\u043f\u043a\u0438":4,"\u043b\u0435\u0433\u043a\u0438\u043c":1,"\u043b\u0435\u0433\u043a\u043e":[3,7],"\u043b\u0456\u0442\u0435\u0440\u0430\u043c\u0438":1,"\u043c\u0430\u0440\u043a":7,"\u043c\u0430\u0440\u043a\u0430":7,"\u043c\u0430\u0440\u043a\u0443\u0432\u0430\u043d\u043d\u044f":3,"\u043c\u0430\u0441\u043a\u0438":7,"\u043c\u0430\u0442\u0438":7,"\u043c\u0430\u0442\u0447":[1,7],"\u043c\u0430\u0442\u0447\u0430\u0445":7,"\u043c\u0430\u0442\u0447\u0443":7,"\u043c\u0430\u0442\u0447\u0456":[1,7],"\u043c\u0430\u0442\u0447\u0456\u0432":1,"\u043c\u0430\u044e\u0442\u044c":[6,7],"\u043c\u0430\u0454":[1,6,7],"\u043c\u0431":7,"\u043c\u0435\u043d\u0448":7,"\u043c\u0435\u043d\u044e":[2,3,4,6],"\u043c\u0435\u0442\u043e\u0434\u0456\u0432":5,"\u043c\u0438":1,"\u043c\u043e\u0432\u0438":7,"\u043c\u043e\u0433\u043b\u0438":7,"\u043c\u043e\u0434\u0438\u0444\u0456\u043a\u0430\u0446\u0456\u0457":7,"\u043c\u043e\u0436\u0435":[2,3,4,7],"\u043c\u043e\u0436\u0435\u0442\u0435":[1,2,3,4,5,6,7],"\u043c\u043e\u0436\u043b\u0438\u0432\u043e":[4,7],"\u043c\u043e\u0436\u043d\u0430":[2,4,7],"\u043c\u043e\u0436\u0443\u0442\u044c":7,"\u043c\u0456\u0436":7,"\u043c\u0456\u0440\u043a\u0443\u0432\u0430\u043d\u044c":1,"\u043c\u0456\u0441\u0442\u0438\u0442\u0438":4,"\u043c\u0456\u0441\u0442\u0438\u0442\u044c":[2,4,7],"\u043c\u0456\u0441\u0446\u0435":[4,7],"\u043c\u0456\u0441\u0446\u044f":4,"\u043c\u0456\u0441\u0446\u0456":4,"\u043d\u0430":[1,2,3,4,5,6,7],"\u043d\u0430\u0432\u0435\u0434\u0435\u043d\u043e\u043c\u0443":6,"\u043d\u0430\u0432\u0435\u0441\u0442\u0438":1,"\u043d\u0430\u0432\u0447\u0430\u043d\u043d\u044f":[4,7],"\u043d\u0430\u0434":1,"\u043d\u0430\u0434\u0437\u0432\u0438\u0447\u0430\u0439\u043d\u043e":1,"\u043d\u0430\u0434\u0456\u0441\u043b\u0430\u0442\u0438":7,"\u043d\u0430\u0437\u0432\u0430":1,"\u043d\u0430\u0439\u0431\u043b\u0438\u0436\u0447\u0456":7,"\u043d\u0430\u0439\u0431\u0456\u043b\u044c\u0448\u0438\u0445":[6,7],"\u043d\u0430\u0439\u0431\u0456\u043b\u044c\u0448\u043e\u044e":7,"\u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u043d\u044f":[1,5],"\u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u0442\u0438":1,"\u043d\u0430\u043c\u0430\u0433\u0430\u044e\u0447\u0438\u0441\u044c":4,"\u043d\u0430\u043c\u0430\u0433\u0430\u0454\u0442\u044c\u0441\u044f":6,"\u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0456":1,"\u043d\u0430\u043f\u0438\u0441\u0430\u0442\u0438":[1,4],"\u043d\u0430\u043f\u043e\u0432\u043d\u044e\u0432\u0430\u0447\u0456":4,"\u043d\u0430\u043f\u0440\u0438\u043a\u043b\u0430\u0434":[4,6,7],"\u043d\u0430\u0441":1,"\u043d\u0430\u0441\u043f\u0440\u0430\u0432\u0434\u0456":1,"\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445":7,"\u043d\u0430\u0441\u0442\u0443\u043f\u043d\u0438\u0439":1,"\u043d\u0430\u0442\u0438\u0441\u043a\u0430\u043d\u043d\u0456":[2,7],"\u043d\u0430\u0442\u0438\u0441\u043d\u0443\u0432\u0448\u0438":7,"\u043d\u0430\u0442\u0438\u0441\u043d\u0443\u0442\u0438":[1,2,7],"\u043d\u0430\u0442\u0438\u0441\u043d\u0456\u0442\u044c":[1,2,5,6,7],"\u043d\u0430\u044f\u0432\u043d\u0456\u0441\u0442\u044c":7,"\u043d\u0435":[2,4,6,7],"\u043d\u0435\u0431\u0443\u0434\u044c":7,"\u043d\u0435\u0432\u0435\u043b\u0438\u043a\u043e\u044e":7,"\u043d\u0435\u043c\u0430\u0454":[5,7],"\u043d\u0435\u043e\u0431\u0445\u0456\u0434\u043d\u043e":4,"\u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e":6,"\u043d\u0435\u043f\u0440\u0438\u0454\u043c\u043d\u043e\u0441\u0442\u0456":1,"\u043d\u0435\u0444\u0456\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u043d\u0435":7,"\u043d\u0438\u0436\u043d\u0456\u0439":7,"\u043d\u0438\u0436\u0447\u0435":[2,6],"\u043d\u0438\u0437\u044c\u043a\u0430":7,"\u043d\u0438\u0437\u044c\u043a\u0438\u0445":1,"\u043d\u0438\u043c":7,"\u043d\u0438\u0445":[1,2,5],"\u043d\u043e\u0432\u0435":7,"\u043d\u043e\u0432\u0438\u0439":[2,7],"\u043d\u043e\u0432\u0443":2,"\u043d\u043e\u043c\u0435\u0440":6,"\u043d\u043e\u043c\u0435\u0440\u0430":4,"\u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u0438\u0439":2,"\u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u043c\u0443":7,"\u043d\u0443":4,"\u043d\u044c\u043e\u0433\u043e":[2,7],"\u043d\u044c\u043e\u043c\u0443":7,"\u043d\u0456":4,"\u043d\u0456\u0436":[2,7],"\u043d\u0456\u043a\u043e\u043b\u0438":[1,2,7],"\u043d\u0456\u044f\u043a\u0438\u0445":1,"\u043e\u0431\u0434\u0443\u0440\u0435\u043d\u0438\u0445":4,"\u043e\u0431\u0434\u0443\u0440\u0435\u043d\u0456":7,"\u043e\u0431\u0434\u0443\u0440\u0438\u0442\u0438":[2,4,6],"\u043e\u0431\u0438\u0434\u0432\u0430":1,"\u043e\u0431\u043c\u0435\u0436\u0435\u043d\u044c":1,"\u043e\u0431\u043e\u0432":7,"\u043e\u0431\u0440\u0430\u043d\u0430":6,"\u043e\u0431\u0440\u0430\u043d\u0438\u0439":[6,7],"\u043e\u0431\u0440\u0430\u043d\u043e":7,"\u043e\u0431\u0440\u0430\u043d\u043e\u0433\u043e":7,"\u043e\u0431\u0440\u0430\u043d\u043e\u0457":[2,7],"\u043e\u0431\u0440\u0430\u043d\u0456":7,"\u043e\u0431\u0445\u0456\u0434\u043d\u043e\u0433\u043e":1,"\u043e\u0433\u043b\u044f\u0434":7,"\u043e\u0434\u0438\u043d":[1,2,7],"\u043e\u0434\u043d\u0430":[1,7],"\u043e\u0434\u043d\u0430\u043a":1,"\u043e\u0434\u043d\u0430\u043a\u043e\u0432\u0438\u0439":6,"\u043e\u0434\u043d\u0430\u043a\u043e\u0432\u0438\u0445":7,"\u043e\u0434\u043d\u043e\u0433\u043e":7,"\u043e\u0434\u043d\u043e\u043c\u0443":2,"\u043e\u0434\u043d\u0443":2,"\u043e\u0434\u043d\u0456\u0454\u0457":7,"\u043e\u0437\u043d\u0430\u0447\u0430\u0454":[1,6,7],"\u043e\u043a":7,"\u043e\u043d\u043e\u0432\u043b\u0435\u043d\u043e":3,"\u043e\u043f\u0435\u0440\u0430\u0446\u0456\u0457":4,"\u043e\u043f\u043e\u0440\u043d\u0438\u0439":7,"\u043e\u043f\u0446\u0456\u044f":[1,4],"\u043e\u0441\u0432\u043e\u0457\u0442\u0438":3,"\u043e\u0441\u043d\u043e\u0432\u043d\u0456":5,"\u043e\u0441\u0442\u0430\u043d\u043d\u044c\u043e\u0433\u043e":7,"\u043e\u0441\u0442\u0430\u043d\u043d\u044c\u043e\u0457":7,"\u043e\u0441\u0442\u0430\u043d\u043d\u044e":3,"\u043e\u0441\u0442\u0430\u043d\u043d\u044f":7,"\u043e\u0441\u0442\u0430\u043d\u043d\u0456\u0439":7,"\u043e\u0441\u0442\u0430\u043d\u043d\u0456\u0445":2,"\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u0456":1,"\u043e\u0441\u044c":[4,7],"\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c":[5,7],"\u043e\u0442\u0440\u0438\u043c\u0430\u0442\u0438":[1,5],"\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e":7,"\u043e\u0447\u0438\u0441\u0442\u0438\u0442\u0438":7,"\u043e\u0447\u0438\u0441\u0442\u0456\u0442\u044c":7,"\u043e\u0447\u0438\u0449\u0443\u0454\u0442\u044c\u0441\u044f":7,"\u043e\u0448\u0443\u043a\u0430\u043d\u0456":[1,3,6],"\u043f\u0430\u043d\u0435\u043b\u044c":[4,7],"\u043f\u0430\u043d\u0435\u043b\u0456":[4,7],"\u043f\u0430\u043f\u043a\u0430":[3,4,7],"\u043f\u0430\u043f\u043a\u0430\u0445":1,"\u043f\u0430\u043f\u043a\u0438":[3,4,6,7],"\u043f\u0430\u043f\u043a\u0443":[1,2,7],"\u043f\u0430\u043f\u043e\u043a":[2,4,5],"\u043f\u0430\u043f\u0446\u0456":[1,2,4,6],"\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0456\u0432":5,"\u043f\u0435\u0432\u043d\u043e\u0457":1,"\u043f\u0435\u0440\u0435\u0432\u0430\u0433\u0438":7,"\u043f\u0435\u0440\u0435\u0432\u0430\u0433\u0443":4,"\u043f\u0435\u0440\u0435\u0432\u0456\u0440\u0438\u0442\u0438":4,"\u043f\u0435\u0440\u0435\u0432\u0456\u0440\u0438\u0442\u044c":4,"\u043f\u0435\u0440\u0435\u0432\u0456\u0440\u043a\u0438":7,"\u043f\u0435\u0440\u0435\u0432\u0456\u0440\u043a\u0443":2,"\u043f\u0435\u0440\u0435\u0433\u043b\u044f\u0434":3,"\u043f\u0435\u0440\u0435\u0433\u043b\u044f\u043d\u0443\u0442\u0438":7,"\u043f\u0435\u0440\u0435\u0434":7,"\u043f\u0435\u0440\u0435\u0434\u0430\u0454":7,"\u043f\u0435\u0440\u0435\u0439\u0434\u0456\u0442\u044c":7,"\u043f\u0435\u0440\u0435\u0439\u043c\u0435\u043d\u0443\u0432\u0430\u043d\u043d\u044f":7,"\u043f\u0435\u0440\u0435\u0439\u043c\u0435\u043d\u0443\u0432\u0430\u0442\u0438":7,"\u043f\u0435\u0440\u0435\u043a\u043e\u043d\u0430\u0439\u0442\u0435\u0441\u044f":[1,5,7],"\u043f\u0435\u0440\u0435\u043a\u043e\u043d\u0430\u0442\u0438\u0441\u044f":1,"\u043f\u0435\u0440\u0435\u043b\u0456\u043a":6,"\u043f\u0435\u0440\u0435\u043c\u0438\u043a\u0430\u0442\u0438":7,"\u043f\u0435\u0440\u0435\u043c\u0438\u043a\u0430\u0447":7,"\u043f\u0435\u0440\u0435\u043c\u043e\u0433\u0442\u0438":6,"\u043f\u0435\u0440\u0435\u043c\u043e\u0436\u0435":6,"\u043f\u0435\u0440\u0435\u043c\u0456\u0441\u0442\u0438\u0442\u0438":7,"\u043f\u0435\u0440\u0435\u043c\u0456\u0449\u0430\u0442\u0438":1,"\u043f\u0435\u0440\u0435\u043c\u0456\u0449\u0430\u0454\u0442\u0435":4,"\u043f\u0435\u0440\u0435\u043c\u0456\u0449\u0435\u043d\u0438\u0439":4,"\u043f\u0435\u0440\u0435\u043c\u0456\u0449\u0435\u043d\u043d\u044f":[1,4,7],"\u043f\u0435\u0440\u0435\u043c\u0456\u0449\u0435\u043d\u043d\u0456":4,"\u043f\u0435\u0440\u0435\u0442\u044f\u0433\u043d\u0443\u0442\u0438":[2,5,6],"\u043f\u0435\u0440\u0448":2,"\u043f\u0435\u0440\u0448\u0430":7,"\u043f\u0435\u0440\u0448\u0435":[1,2],"\u043f\u0435\u0440\u0448\u0438\u0439":[1,2,6,7],"\u043f\u0435\u0440\u0448\u0438\u043c":7,"\u043f\u0435\u0440\u0448\u043e\u0457":3,"\u043f\u0438\u0442\u0430\u043d\u043d\u044f":3,"\u043f\u043e":[1,7],"\u043f\u043e\u0431\u0430\u0447\u0438\u0442\u0438":4,"\u043f\u043e\u0432":7,"\u043f\u043e\u0432\u0435\u0440\u043d\u0435\u0442\u044c\u0441\u044f":7,"\u043f\u043e\u0432\u0435\u0440\u043d\u0443\u0442\u0438\u0441\u044f":7,"\u043f\u043e\u0432\u0438\u043d\u0435\u043d":6,"\u043f\u043e\u0432\u0438\u043d\u043d\u0456":[1,4,7],"\u043f\u043e\u0432\u043d\u043e\u043c\u0443":4,"\u043f\u043e\u0432\u0442\u043e\u0440\u043d\u0435":3,"\u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e":[1,4],"\u043f\u043e\u0432\u0442\u043e\u0440\u044e\u0432\u0430\u043d\u0456":7,"\u043f\u043e\u0432\u0442\u043e\u0440\u044e\u0454":7,"\u043f\u043e\u0433\u043b\u044f\u043d\u0443\u0442\u0438":3,"\u043f\u043e\u0434\u0430\u043b\u044c\u0448\u043e\u0457":7,"\u043f\u043e\u0434\u0438\u0432\u0456\u0442\u044c\u0441\u044f":5,"\u043f\u043e\u0434\u0440\u043e\u0431\u0438\u0446\u0456":7,"\u043f\u043e\u0437\u0438\u0446\u0456\u044e":6,"\u043f\u043e\u0437\u0438\u0446\u0456\u044f":2,"\u043f\u043e\u0437\u0438\u0446\u0456\u0457":6,"\u043f\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u043e":[1,5,7],"\u043f\u043e\u0437\u043d\u0430\u0447\u0438\u0442\u0438":[5,7],"\u043f\u043e\u043a\u0430\u0436\u0435":7,"\u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0438":3,"\u043f\u043e\u043a\u0430\u0437\u0443\u0454":7,"\u043f\u043e\u043a\u0438":5,"\u043f\u043e\u043b\u0435":7,"\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u043d\u044f":[1,7],"\u043f\u043e\u043b\u044f\u0433\u0430\u0454":1,"\u043f\u043e\u043c\u0438\u043b\u043a\u043e\u0432\u0438\u043c\u0438":7,"\u043f\u043e\u043c\u0438\u043b\u043a\u043e\u0432\u0438\u0445":[5,7],"\u043f\u043e\u043c\u0456\u0442\u0438\u0442\u0438":[1,7],"\u043f\u043e\u043c\u0456\u0447\u0435\u043d\u0456":7,"\u043f\u043e\u0440\u043e\u0436\u043d\u044f":4,"\u043f\u043e\u0440\u043e\u0436\u043d\u0456\u0445":4,"\u043f\u043e\u0440\u0443\u0447":7,"\u043f\u043e\u0440\u0443\u0448\u0435\u043d\u0456":7,"\u043f\u043e\u0440\u044f\u0434\u043a\u0443":7,"\u043f\u043e\u0440\u044f\u0434\u043e\u043a":[6,7],"\u043f\u043e\u0440\u0456\u0432\u043d\u044e\u0454\u0442\u0435":4,"\u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044e":7,"\u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f":[1,2,4,6,7],"\u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f\u043c":[5,7],"\u043f\u043e\u0441\u0438\u043b\u0430\u0442\u0438\u0441\u044f":4,"\u043f\u043e\u0441\u0438\u043b\u0430\u044e\u0442\u044c\u0441\u044f":4,"\u043f\u043e\u0441\u0438\u043b\u0430\u0454\u0442\u0435":1,"\u043f\u043e\u0442\u043e\u0447\u043d\u0456":7,"\u043f\u043e\u0442\u0440\u0456\u0431\u043d\u043e":6,"\u043f\u043e\u0442\u0443\u0436\u043d\u0438\u0439":6,"\u043f\u043e\u0442\u0456\u043c":[1,5,6,7],"\u043f\u043e\u0447\u0430\u043b\u0438":5,"\u043f\u043e\u0447\u0430\u0442\u0438":7,"\u043f\u043e\u0447\u0430\u0442\u043a\u043e\u0432\u0438\u0439":4,"\u043f\u043e\u0447\u0430\u0442\u043a\u0443":[4,7],"\u043f\u043e\u0447\u0435\u043a\u0430\u0439\u0442\u0435":5,"\u043f\u043e\u0448\u0443\u043a":7,"\u043f\u043e\u0448\u0443\u043a\u0443":[3,7],"\u043f\u043e\u044f\u0441\u043d\u044e\u044e\u0447\u0438":[4,7],"\u043f\u0440\u0430\u0432":1,"\u043f\u0440\u0430\u0432\u0430":1,"\u043f\u0440\u0430\u0432\u0434\u0430":7,"\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e":1,"\u043f\u0440\u0430\u0432\u043a\u0430":7,"\u043f\u0440\u0430\u0432\u043e":4,"\u043f\u0440\u0430\u0432\u043e\u043c":6,"\u043f\u0440\u0430\u0432\u043e\u0440\u0443\u0447":6,"\u043f\u0440\u0430\u0432\u0443":6,"\u043f\u0440\u0430\u043f\u043e\u0440\u0435\u0446\u044c":[4,7],"\u043f\u0440\u0438":[1,2,4,7],"\u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438":6,"\u043f\u0440\u0438\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044f":[4,7],"\u043f\u0440\u0438\u0439\u0434\u0435":7,"\u043f\u0440\u0438\u0439\u043d\u044f\u0442\u0456":7,"\u043f\u0440\u0438\u043a\u043b\u0430\u0434":[1,4],"\u043f\u0440\u0438\u043c\u0456\u0440\u043d\u0438\u043a\u0430\u0445":7,"\u043f\u0440\u0438\u043d\u0430\u0439\u043c\u043d\u0456":1,"\u043f\u0440\u0438\u043f\u0443\u0441\u043a\u0430\u0454":7,"\u043f\u0440\u0438\u0447\u0438\u043d\u0430":7,"\u043f\u0440\u043e":[1,3,5],"\u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0438":1,"\u043f\u0440\u043e\u0431\u0456\u043b":1,"\u043f\u0440\u043e\u0431\u0456\u043b\u0438":4,"\u043f\u0440\u043e\u0433\u0430\u043b\u0438\u043d\u0438":4,"\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u0438":[4,7],"\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u0443":7,"\u043f\u0440\u043e\u0434\u043e\u0432\u0436\u0438\u0442\u0438":7,"\u043f\u0440\u043e\u0441\u0442\u0430":2,"\u043f\u0440\u043e\u0441\u0442\u0438\u0445":7,"\u043f\u0440\u043e\u0441\u0442\u043e":[5,7],"\u043f\u0440\u043e\u0441\u0442\u043e\u043c\u0443":7,"\u043f\u0440\u043e\u0441\u0442\u043e\u0440\u0456":7,"\u043f\u0440\u043e\u0441\u0443\u0432\u0430\u0442\u0438":[1,7],"\u043f\u0440\u043e\u0441\u0443\u043d\u0443\u0442\u0438\u0445":7,"\u043f\u0440\u043e\u0446\u0435\u0441":5,"\u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0432":5,"\u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u0438":1,"\u043f\u0440\u043e\u0456\u0433\u043d\u043e\u0440\u043e\u0432\u0430\u043d\u0456":7,"\u043f\u0440\u044f\u043c\u043e":2,"\u043f\u0440\u0456\u043e\u0440\u0438\u0442\u0435\u0442":7,"\u043f\u0440\u0456\u043e\u0440\u0438\u0442\u0435\u0442\u0438":6,"\u043f\u0440\u0456\u043e\u0440\u0438\u0442\u0435\u0442\u0456\u0432":3,"\u043f\u0443\u043d\u043a\u0442":[2,4,6,7],"\u043f\u0443\u043d\u043a\u0442\u043e\u043c":[4,7],"\u043f\u0443\u043d\u043a\u0442\u0443":7,"\u043f\u0456\u0434":7,"\u043f\u0456\u0434\u043c\u043d\u043e\u0436\u0438\u043d\u0438":7,"\u043f\u0456\u0434\u043f\u0430\u043f\u043a\u0438":2,"\u043f\u0456\u0434\u043f\u0430\u043f\u043a\u0443":2,"\u043f\u0456\u0434\u0441\u0443\u043c\u043a\u0443":[1,2],"\u043f\u0456\u0434\u0442\u0440\u0438\u043c\u043a\u0438":1,"\u043f\u0456\u0434\u0442\u0440\u0438\u043c\u0443\u0454":7,"\u043f\u0456\u0441\u043b\u044f":[1,4,7],"\u0440\u0430\u0437\u043e\u043c":[1,7],"\u0440\u0430\u043c\u043a\u0438":[4,7],"\u0440\u0430\u043d\u0456\u0448\u0435":6,"\u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u0438\u0439":[4,7],"\u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u0438\u0445":[4,7],"\u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0433\u043e":[4,7],"\u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u0456":7,"\u0440\u0435\u0433\u0456\u0441\u0442\u0440\u0443":7,"\u0440\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438":5,"\u0440\u0435\u0436\u0438\u043c":[1,7],"\u0440\u0435\u0436\u0438\u043c\u0456":[1,7],"\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442":1,"\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u0445":[5,7],"\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0438":[1,3,5,6],"\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0443":7,"\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0456":7,"\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0456\u0432":[1,3,5],"\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0454\u0442\u044c\u0441\u044f":7,"\u0440\u0435\u0448\u0442\u0443":5,"\u0440\u043e\u0431\u0438\u0442\u0435":7,"\u0440\u043e\u0431\u0438\u0442\u0438":[1,5],"\u0440\u043e\u0431\u0438\u0442\u044c":6,"\u0440\u043e\u0431\u0438\u0442\u044c\u0441\u044f":6,"\u0440\u043e\u0434\u0443":7,"\u0440\u043e\u0437\u0433\u043b\u044f\u0434\u0430\u0442\u0438\u043c\u0435":4,"\u0440\u043e\u0437\u043a\u0440\u0438\u0432\u0430\u0442\u0438":7,"\u0440\u043e\u0437\u043a\u0440\u0438\u0442\u0438":7,"\u0440\u043e\u0437\u043c\u0456\u0440":[6,7],"\u0440\u043e\u0437\u043c\u0456\u0440\u043e\u043c":[6,7],"\u0440\u043e\u0437\u0440\u043e\u0431\u043b\u0435\u043d\u0438\u0439":1,"\u0440\u043e\u0437\u0443\u043c\u043d\u0438\u0439":6,"\u0440\u043e\u0437\u0448\u0438\u0440\u0435\u043d\u043d\u044f\u043c":7,"\u0440\u043e\u0437\u0448\u0438\u0440\u0435\u043d\u043d\u044f\u043c\u0438":4,"\u0440\u0443\u0447\u043a\u0438":4,"\u0440\u044f\u0434\u043a\u043e\u043c":1,"\u0440\u044f\u0434\u043a\u0443":4,"\u0440\u044f\u0434\u043e\u043a":7,"\u0440\u0456\u0437\u043d\u0438\u043c\u0438":4,"\u0440\u0456\u0437\u043d\u0456":[5,7],"\u0441":1,"\u0441\u0430\u043c\u0435":7,"\u0441\u0430\u043c\u0438\u0439":4,"\u0441\u0430\u043c\u043e\u043c\u0443":1,"\u0441\u0430\u043c\u0456":7,"\u0441\u0432\u043e\u0433\u043e":7,"\u0441\u0432\u043e\u044e":[1,7],"\u0441\u0432\u043e\u0454":7,"\u0441\u0432\u043e\u0454\u043c\u0443":3,"\u0441\u0432\u0456\u0436\u0456":7,"\u0441\u0432\u0456\u0439":2,"\u0441\u0435\u0431\u0435":[4,7],"\u0441\u0435\u0440\u0435\u0434":7,"\u0441\u0438\u043b\u0443":7,"\u0441\u0438\u043d\u0456\u0439":7,"\u0441\u0438\u043d\u0456\u043c\u0438":1,"\u0441\u0438\u0441\u0442\u0435\u043c\u0430":1,"\u0441\u043a\u0430\u043d\u0435\u0440":1,"\u0441\u043a\u0430\u043d\u0443\u0432\u0430\u043d\u043d\u044f":[1,2,3,5,7],"\u0441\u043a\u0430\u043d\u0443\u0432\u0430\u0442\u0438\u0441\u044f":2,"\u0441\u043a\u0430\u043d\u0443\u0454\u043c\u043e":1,"\u0441\u043a\u0430\u0441\u0443\u0432\u0430\u0442\u0438":7,"\u0441\u043a\u043b\u0430\u0434\u0430\u0442\u0438\u0441\u044f":7,"\u0441\u043a\u043e\u043f\u0456\u044e\u0432\u0430\u0442\u0438":7,"\u0441\u043a\u043e\u043f\u0456\u044e\u0439\u0442\u0435":7,"\u0441\u043a\u043e\u0440\u043e\u0447\u0435\u043d\u0456":4,"\u0441\u043b\u0456\u0434\u0443\u044e\u0442\u044c":6,"\u0441\u043c\u0456\u0442\u0442\u044f":7,"\u0441\u043e\u0431\u043e\u044e":7,"\u0441\u043e\u0440\u0442\u0443\u0432\u0430\u043d\u043d\u044f":[1,6,7],"\u0441\u043e\u0440\u0442\u0443\u0432\u0430\u0442\u0438":7,"\u0441\u043e\u0440\u0442\u0443\u044e\u0442\u044c\u0441\u044f":7,"\u0441\u043f\u0430\u0434\u0430\u043d\u043d\u044f\u043c":7,"\u0441\u043f\u0430\u0434\u043d\u043e\u043c\u0443":6,"\u0441\u043f\u0435\u0446\u0456\u0430\u043b\u044c\u043d\u043e\u0457":[4,7],"\u0441\u043f\u0438\u0441\u043a\u043e\u043c":2,"\u0441\u043f\u0438\u0441\u043a\u0443":[2,6,7],"\u0441\u043f\u0438\u0441\u043e\u043a":[2,6,7],"\u0441\u043f\u043b\u0438\u0432\u0430\u044e\u0447\u0435":2,"\u0441\u043f\u043e\u0441\u0456\u0431":[2,7],"\u0441\u043f\u043e\u0447\u0430\u0442\u043a\u0443":[6,7],"\u0441\u043f\u0440\u0430\u0432\u0430":6,"\u0441\u043f\u0440\u0430\u0432\u0443":1,"\u0441\u043f\u0440\u0438\u044f\u043d\u043d\u044f":7,"\u0441\u043f\u0440\u0438\u044f\u043d\u043d\u0456":1,"\u0441\u043f\u0456\u0432\u043f\u0430\u0434\u0430\u0454":1,"\u0441\u0442\u0430\u043d":[1,2,7],"\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u043c":7,"\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u0445":5,"\u0441\u0442\u0430\u043d\u0443":2,"\u0441\u0442\u0430\u0440\u0442":3,"\u0441\u0442\u0432\u043e\u0440\u0438\u0442\u0438":1,"\u0441\u0442\u0432\u043e\u0440\u044e\u0432\u0430\u0442\u0438":7,"\u0441\u0442\u043e\u0432\u043f\u0435\u0446\u044c":7,"\u0441\u0442\u043e\u0432\u043f\u0446\u0456":7,"\u0441\u0442\u043e\u0432\u043f\u0446\u0456\u0432":7,"\u0441\u0442\u043e\u0440\u0456\u043d\u043a\u0430":3,"\u0441\u0442\u0440\u0443\u043c":7,"\u0441\u0442\u0440\u0443\u043c\u0443":1,"\u0441\u0442\u0440\u0456\u043b\u043a\u0443":6,"\u0442\u0430":[4,5,7],"\u0442\u0430\u043a":[1,6,7],"\u0442\u0430\u043a\u0438\u0439":4,"\u0442\u0430\u043a\u0438\u043c":[1,7],"\u0442\u0430\u043a\u0438\u0445":7,"\u0442\u0430\u043a\u043e\u0436":[4,7],"\u0442\u0430\u043a\u043e\u043c\u0443":1,"\u0442\u0430\u043a\u0456":1,"\u0442\u0430\u043c":1,"\u0442\u0432\u0435\u0440\u0434\u043e\u0441\u0442\u0456":1,"\u0442\u0435":[1,4,7],"\u0442\u0435\u043a\u0441\u0442\u0443":7,"\u0442\u0438":7,"\u0442\u0438\u043c":7,"\u0442\u0438\u043c\u0447\u0430\u0441\u043e\u0432\u0443":1,"\u0442\u0438\u043f":7,"\u0442\u0438\u043f\u043e\u043c":7,"\u0442\u0438\u043f\u0443":7,"\u0442\u043e":7,"\u0442\u043e\u0433\u043e":[4,7],"\u0442\u043e\u0434\u0456":1,"\u0442\u043e\u0439":4,"\u0442\u043e\u043c\u0443":[1,7],"\u0442\u0440\u0438\u043c\u0430\u0442\u0438":1,"\u0442\u0440\u044e\u043a":6,"\u0442\u0443\u0442":6,"\u0442\u0456\u0439":2,"\u0442\u0456\u043b\u044c\u043a\u0438":[1,2,3,4,5,6],"\u0442\u0456\u0454\u0457":[1,7],"\u0443":[2,4,6,7],"\u0443\u0431\u0443\u0432\u0430\u043d\u043d\u044f":7,"\u0443\u0432\u0430\u0433\u0443":7,"\u0443\u0433":1,"\u0443\u0437\u0433\u043e\u0434\u0436\u0435\u043d\u043d\u044f":7,"\u0443\u043a\u043b\u0430\u0441\u0442\u0438":4,"\u0443\u043f\u043e\u0434\u043e\u0431\u0430\u043d\u043d\u044f":3,"\u0443\u0441\u043f\u0430\u0434\u043a\u043e\u0432\u0443\u0454":2,"\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438":1,"\u0443\u0442\u0438\u043b\u0456\u0442\u0438":1,"\u0443\u0442\u0440\u0438\u043c\u0443\u0432\u0430\u0442\u0438":7,"\u0443\u0442\u0440\u0438\u043c\u0443\u0439\u0442\u0435":7,"\u0443\u044f\u0432\u043b\u0435\u043d\u043d\u044f":7,"\u0444\u0430\u0439\u043b":[2,4,5,6,7],"\u0444\u0430\u0439\u043b\u0430":7,"\u0444\u0430\u0439\u043b\u0438":[2,4,5,7],"\u0444\u0430\u0439\u043b\u0443":[1,3,4,5,6,7],"\u0444\u0430\u0439\u043b\u0456":7,"\u0444\u0430\u0439\u043b\u0456\u0432":[1,6,7],"\u0444\u0430\u043a\u0442\u0438\u0447\u043d\u043e\u0457":7,"\u0444\u043e\u0440\u043c\u0430\u0442":4,"\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430":7,"\u0444\u0443\u043d\u043a\u0446\u0456\u044f":7,"\u0444\u0443\u043d\u043a\u0446\u0456\u0457":7,"\u0444\u0456\u043a\u0441\u0430\u0446\u0456\u0457":1,"\u0444\u0456\u043b\u044c\u0442\u0440":7,"\u0444\u0456\u043b\u044c\u0442\u0440\u0430":[1,4,7],"\u0444\u0456\u043b\u044c\u0442\u0440\u0430\u0446\u0456\u044f":[3,4],"\u0444\u0456\u043b\u044c\u0442\u0440\u0430\u0446\u0456\u0457":[4,7],"\u0444\u0456\u043b\u044c\u0442\u0440\u043e\u043c":7,"\u0444\u0456\u043b\u044c\u0442\u0440\u0443\u0454\u0442\u044c\u0441\u044f":7,"\u0444\u0456\u043b\u044c\u0442\u0440\u0456\u0432":7,"\u0445":2,"\u0445\u043e\u0440\u043e\u0448\u0438\u0439":4,"\u0445\u043e\u0442\u0456\u043b\u0438":1,"\u0445\u043e\u0447\u0430":[3,7],"\u0445\u043e\u0447\u0435\u0442\u0435":[1,2,7],"\u0445\u043e\u0447\u0443":7,"\u0446\u0435":[2,3,4,5,6,7],"\u0446\u0435\u0439":[2,4,6,7],"\u0446\u0438\u043c\u0438":7,"\u0446\u0438\u0445":2,"\u0446\u044c\u043e\u0433\u043e":[3,4,5,7],"\u0446\u044c\u043e\u043c\u0443":[1,2],"\u0446\u044e":[1,2,4,7],"\u0446\u044f":[4,7],"\u0446\u0456":[4,7],"\u0446\u0456\u0439":[2,6],"\u0446\u0456\u043b\u0438\u0439":7,"\u0446\u0456\u043d\u043d\u043e\u0441\u0442\u0456":6,"\u0446\u0456\u0454\u044e":7,"\u0446\u0456\u0454\u0457":2,"\u0447\u0430\u0441":7,"\u0447\u0430\u0441\u043e\u043c":7,"\u0447\u0430\u0441\u0442\u0438\u043d\u043e\u044e":7,"\u0447\u0430\u0441\u0442\u0438\u043d\u0443":1,"\u0447\u0430\u0441\u0442\u0438\u043d\u0456":7,"\u0447\u0430\u0441\u0442\u0456":3,"\u0447\u0430\u0441\u0443":1,"\u0447\u0435\u0440\u0435\u0437":[1,4,6],"\u0447\u0438":7,"\u0447\u0438\u043d\u043e\u043c":[1,7],"\u0447\u0438\u0442\u0430\u043d\u043d\u044f":3,"\u0447\u043b\u0435\u043d":1,"\u0447\u043e\u043c\u0443":7,"\u0447\u043e\u0440\u043d\u0438\u0439":7,"\u0447\u0443\u0442\u043b\u0438\u0432\u0456":7,"\u0447\u0456\u0442\u043a\u0435":7,"\u0448\u0432\u0438\u0434\u043a\u0438\u0439":3,"\u0448\u0432\u0438\u0434\u043a\u043e":[5,7],"\u0448\u043b\u044f\u0445":[4,7],"\u0448\u043b\u044f\u0445\u043e\u043c":4,"\u0448\u043b\u044f\u0445\u0443":[1,4],"\u0448\u0443\u043a\u0430\u0442\u0438\u0441\u044f":7,"\u0448\u0443\u043a\u0430\u0454\u0442\u0435":3,"\u0449\u0435":1,"\u0449\u043e":[2,4,5,6,7],"\u0449\u043e\u0431":[2,3,4,5,7],"\u0449\u043e\u0439\u043d\u043e":5,"\u044f":[4,6,7],"\u044f\u0432\u0438\u0442\u044c\u0441\u044f":2,"\u044f\u0432\u043b\u044f\u0454":7,"\u044f\u0432\u043d\u043e":2,"\u044f\u0437\u0430\u043d\u0438\u0439":7,"\u044f\u0437\u0430\u043d\u043e\u0433\u043e":7,"\u044f\u0437\u0430\u043d\u0456":7,"\u044f\u0437\u043a\u043e\u0432\u043e":7,"\u044f\u0437\u043a\u0443":6,"\u044f\u043a":[1,4,7],"\u044f\u043a\u0430":[1,4,7],"\u044f\u043a\u0438\u0439":[1,6,7],"\u044f\u043a\u0438\u043c\u0438":6,"\u044f\u043a\u0438\u0445":1,"\u044f\u043a\u043e\u043c\u0443":6,"\u044f\u043a\u043e\u0441\u0442\u0456":7,"\u044f\u043a\u0443":1,"\u044f\u043a\u0449\u043e":[1,2,3,4,5,6,7],"\u044f\u043a\u0456":[2,4,5,6,7],"\u0454":[4,5,6,7],"\u0456":[1,2,3,4,5,6],"\u0456\u0433\u043d\u043e\u0440\u043e\u0432\u0430\u043d\u0438\u0445":7,"\u0456\u0433\u043d\u043e\u0440\u0443\u0432\u0430\u0442\u0438":4,"\u0456\u0433\u043d\u043e\u0440\u0443\u0432\u0430\u0442\u0438\u0441\u044f":7,"\u0456\u0433\u043d\u043e\u0440\u0443\u044e\u0442\u044c":7,"\u0456\u0434\u0435\u044f":3,"\u0456\u0437":7,"\u0456\u043c":[4,6,7],"\u0456\u043c\u0435\u043d":4,"\u0456\u043d\u0432\u0430\u043b\u0456\u0434\u0456\u0432":5,"\u0456\u043d\u0434\u0435\u043a\u0441":3,"\u0456\u043d\u0434\u0435\u043a\u0441\u043d\u0438\u0439":4,"\u0456\u043d\u043e\u0434\u0456":6,"\u0456\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0456\u0432":7,"\u0456\u043d\u0448\u0456":[2,7],"\u0456\u043d\u0448\u0456\u0439":7,"\u0456\u0441\u043d\u0443\u0454":[1,4],"\u0456\u0441\u0442\u0438\u043d\u043d\u043e\u0433\u043e":7,"\u0457\u0445":[1,2,4,7],"\u0457\u0457":5,"ale\u0161":0,"byte":0,"case":0,"default":0,"export":0,"import":0,"long":0,"new":0,"switch":0,"t\u00e4tzner":0,"try":0,"while":0,Added:0,But:0,EXE:7,The:0,These:0,Was:0,abil:0,about:0,accident:0,action:0,activ:0,add:[0,2,7],added:0,adding:0,affect:0,after:0,again:0,alarm:0,algorithm:0,all:0,allow:0,alreadi:0,also:0,analyz:0,anh:0,annoy:0,anymor:0,anywai:0,apertur:[0,2],app:0,appli:0,applic:0,arbitrari:0,arch:0,archive2015:0,aren:0,armenian:0,ascii:0,ask:0,attribut:0,attributeerror:0,audio:0,auto:0,automat:0,avoid:0,awar:0,back:0,backend:0,bad:0,bar:[0,6],base:0,batchmod:1,becam:0,been:0,begin:0,behavior:0,being:0,between:0,big:0,bin:0,bind:0,bit:0,block:0,blue:0,brazilian:0,bring:0,broken:0,bsd:0,bug:0,build:0,bump:0,bundl:0,button:0,cach:0,call:0,came:0,can:0,cancel:0,caus:0,ceil:0,cell:0,certain:0,chang:0,changelog:3,charact:0,chines:0,choos:0,chosen:0,clear:0,clearer:0,click:0,cmd:0,cocoa:0,collect:0,color:0,column:0,comboboxmodel:0,come:0,command:[0,7],comparison:0,compat:0,complement:0,complet:0,configur:0,confus:0,contain:0,content:[0,3],context:0,control:7,convers:0,convert:0,copi:0,core:0,correct:0,correctli:0,corrupt:0,couldn:0,count:0,coupl:0,crash:0,creat:0,creation:0,criteria:0,csv:0,custom:0,czech:0,date:0,debug:0,dee:0,delet:[0,7],delta:[0,7],depend:0,descriptor:0,design:0,destin:0,detail:0,detect:0,detinov:0,dialog:0,directori:[0,4],disabl:0,discard:0,displai:0,document:0,doe:0,don:0,doubl:0,drag:0,dramat:0,drop:0,due:0,dupe:0,dupeguru:[0,2,4,5,6,7],duplic:0,dure:0,dutch:0,each:0,edit:0,effici:0,elegantli:0,empti:0,enabl:0,end:0,engin:0,english:1,eric:0,error:0,especi:0,even:0,exact:0,exclud:0,exclus:0,exe:4,exist:0,express:[0,4,7],ext:4,extens:0,fact:0,fairwar:[0,1],fals:0,faq:1,featur:0,feedback:0,fetch:0,few:0,field:[0,7],figueiredo:0,file:[0,4],filenam:0,filter:0,find:0,finder:[0,7],fix:0,focu:0,folder:0,font:0,foo:6,foobar:4,format:0,found:0,frank:0,freez:0,french:0,from:0,fuzzi:0,gabriel:0,german:0,get:0,ghost:0,github:0,glitch:0,going:0,gplv3:0,greatli:0,greek:0,gregor:0,group:0,gui:0,had:0,handl:0,happen:0,hard:0,hardcod:0,hardlink:[0,4],has:[0,7],have:0,help:0,here:0,homepag:3,hour:0,how:0,hrant:0,html:0,http:0,icon:0,ignor:0,igor:0,improv:0,inaccuraci:0,inconveni:0,info:[0,4,7],inform:7,initi:0,insensit:0,instead:0,interfac:0,intern:0,internation:0,introduc:0,invoc:0,involv:0,iphoto:[0,2,7],issu:0,italian:0,item:[0,7],itun:[0,2,7],job:0,jumpi:0,just:0,keep:0,keybind:0,kind:0,korean:0,koutilelli:0,kyril:0,larg:0,last:0,latin:0,launch:0,length:0,librari:2,licens:0,like:0,limit:0,linux:[0,4,7],lion:0,list:0,littl:0,load:0,local:0,localis:0,locat:0,longer:0,longest:0,lose:0,lost:0,lot:0,low:0,mac:[0,7],machin:0,maco:0,made:0,main:0,make:0,mani:0,mark:0,marker:0,mass:0,match:0,mayb:0,mean:0,media:0,memori:0,menu:[0,7],merg:0,messag:0,might:0,min:0,minimum:0,minor:0,mishandl:0,mistakenli:0,mode:[0,1],more:0,mostli:0,move:[0,7],mp3:0,much:0,multipl:0,music:0,mydestin:4,nah:0,name:0,nasti:0,nehyba:0,net:0,non:[0,7],note:2,noth:0,notic:0,now:[0,7],number:0,numer:[0,7],object:0,obsolet:0,occasion:0,occur:0,ohanyan:0,onc:0,one:0,onli:0,open:0,oper:0,option:[0,7],order:0,outdat:1,overwrit:0,packag:0,panel:0,paolo:0,part:0,path:0,pavlov:0,permiss:0,permissionerror:0,petrashko:0,phan:0,phase:0,pictur:0,place:0,polish:0,pop:0,posit:0,possibl:0,post:0,power:0,predict:0,pref:0,prefer:0,present:0,pretti:0,prevent:0,previou:0,priorit:0,problem:0,process:0,program:4,progress:0,propag:0,put:0,pyqt:0,python:0,qestion:1,quick:3,quicklook:0,quit:0,random:0,read:0,realli:0,recent:0,recycl:0,reduc:0,ref:0,refactor:0,refer:0,refresh:0,registr:0,regular:0,relat:0,releas:0,relev:0,reliabl:0,reload:0,rememb:0,remind:0,remov:0,renam:0,replac:0,report:0,requir:0,reset:0,respons:0,restor:0,result:0,revamp:0,reveal:0,rewrit:0,right:0,roman:0,rossi:0,round:0,run:0,russian:0,same:0,save:0,scan:0,scanner:0,screen:0,search:7,section:7,see:1,seek:0,seldom:0,select:0,send:0,sensibl:0,sent:0,separ:0,set:0,shelv:0,shift:7,shortest:0,show:0,side:0,sierra:0,significantli:0,similar:0,simpli:0,simplifi:0,sinc:0,situat:0,size:0,small:0,smartli:0,soft:0,softwar:0,some:0,somefil:4,somefold:4,sometim:0,sort:0,space:7,spanish:0,sparkl:0,speed:0,sphinx:0,stall:0,standard:0,start:[0,3],startup:0,state:0,statu:0,sticki:0,stop:0,stuck:0,subargu:6,subfold:[0,4],subsequ:0,superdiffprog:4,support:0,sure:0,surrog:0,symlink:0,sync:0,system:0,systemat:0,tabl:0,technic:0,tell:0,temporarili:0,text:0,than:0,them:0,therefor:0,thi:[0,1],thread:0,threshold:0,through:0,tiger:0,too:0,toolbar:7,trash:0,tweak:0,type:0,typo:0,ubuntu:0,ukrainian:0,under:0,unicod:0,unicodeencodeerror:0,univers:0,unmaintain:0,unpaid:0,unsav:0,updat:0,upgrad:0,upon:0,usag:0,use_regexp:0,used:0,useful:0,user:[0,4],using:0,valu:0,variou:0,veri:0,version:[0,1],victor:0,vietnames:0,vista:0,visual:0,wai:0,want:0,warn:[0,7],wasn:0,weber:0,weight:0,well:0,were:0,when:0,where:0,which:0,whole:0,window:[0,7],woe:0,wonder:0,word:0,work:0,would:0,wouldn:0,writabl:0,wrong:0,www:0,xhtml:[0,7],yeah:0,you:0,your:0,yuri:0},titles:["Changelog","\u0427\u0430\u0441\u0442\u0456 \u043f\u0438\u0442\u0430\u043d\u043d\u044f","\u0412\u0438\u0431\u0456\u0440 \u043f\u0430\u043f\u043a\u0438","dupeGuru help","\u0423\u043f\u043e\u0434\u043e\u0431\u0430\u043d\u043d\u044f","\u0428\u0432\u0438\u0434\u043a\u0438\u0439 \u0441\u0442\u0430\u0440\u0442","\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u0435 \u043f\u0440\u0456\u043e\u0440\u0438\u0442\u0435\u0442\u0456\u0432 \u0434\u0443\u0431\u043b\u0456\u043a\u0430\u0442\u0456\u0432","\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0438"],titleterms:{"\u0430\u043b\u0435":1,"\u0431\u0435\u0437\u043f\u0435\u0447\u043d\u043e":1,"\u0432":1,"\u0432\u0438\u0431\u0456\u0440":[2,7],"\u0432\u0438\u0434\u0430\u043b\u0438\u0442\u0438":1,"\u0432\u0438\u0437\u043d\u0430\u0447\u0435\u043d\u043e\u0457":1,"\u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0432\u0430\u0442\u0438":1,"\u0432\u0441\u0456":1,"\u0432\u0456\u0434\u0437\u043d\u0430\u0447\u0438\u0442\u0438":1,"\u0432\u0456\u0434\u043a\u0438\u0434\u0430\u0454\u0442\u044c\u0441\u044f":1,"\u0432\u0456\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0430":1,"\u0432\u0456\u0434\u043f\u0440\u0430\u0432\u0438\u0442\u0438":1,"\u0432\u0456\u043d":1,"\u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c":1,"\u0433\u0440\u0443\u043f\u0438":7,"\u0434\u0435\u043b\u044c\u0442\u0430":7,"\u0434\u0435\u043c\u043e":1,"\u0434\u0435\u0440\u0436\u0430\u0432":2,"\u0434\u043e\u0440\u043e\u0431\u0438\u0442\u0438":[1,2,7],"\u0434\u0443\u0431\u043b\u044e\u0432\u0430\u0442\u0438":1,"\u0434\u0443\u0431\u043b\u0456\u043a\u0430\u0442":7,"\u0434\u0443\u0431\u043b\u0456\u043a\u0430\u0442\u0438":1,"\u0434\u0443\u0431\u043b\u0456\u043a\u0430\u0442\u0456\u0432":6,"\u0434\u0456\u044f":7,"\u0437":1,"\u0437\u0430":1,"\u0437\u043d\u0430\u043a":1,"\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044f":7,"\u0437\u0440\u043e\u0431\u0438\u0442\u0438":1,"\u0439\u043e\u0433\u043e":1,"\u043a\u043e\u0440\u0437\u0438\u043d\u0443":1,"\u043a\u043e\u0440\u043e\u0431\u043a\u0443":1,"\u043a\u0440\u0430\u0449\u0435":1,"\u043c\u0430\u0440\u043a\u0443\u0432\u0430\u043d\u043d\u044f":7,"\u043c\u0435\u043d\u0435":1,"\u043c\u0435\u043d\u044e":7,"\u043c\u0435\u043d\u0456":1,"\u043c\u043e\u0436\u0435":1,"\u043c\u043e\u0436\u0443":1,"\u043d\u0430\u043c\u0430\u0433\u0430\u0432\u0441\u044f":1,"\u043d\u0430\u0441\u043a\u0456\u043b\u044c\u043a\u0438":1,"\u043d\u0435":1,"\u043d\u0456\u0436":1,"\u043e\u0431\u043c\u0435\u0436\u0435\u043d\u043d\u044f":1,"\u043e\u0448\u0443\u043a\u0430\u043d\u0456":7,"\u043f\u0430\u043f\u043a\u0430":[1,2],"\u043f\u0430\u043f\u043a\u0438":[1,2],"\u043f\u0435\u0440\u0435\u0433\u043b\u044f\u0434":7,"\u043f\u0438\u0442\u0430\u043d\u043d\u044f":1,"\u043f\u043e\u0432\u0438\u043d\u0435\u043d":1,"\u043f\u043e\u0432\u0442\u043e\u0440\u043d\u0435":6,"\u043f\u043e\u0432\u0456\u0434\u043e\u043c\u043b\u0435\u043d\u043d\u044f":1,"\u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0438":7,"\u043f\u0440\u043e":7,"\u043f\u0440\u0456\u043e\u0440\u0438\u0442\u0435\u0442\u0456\u0432":6,"\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0438":7,"\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0456\u0432":7,"\u0440\u043e\u0431\u0438\u0442\u044c":1,"\u0440\u044f\u0434\u043a\u0443":1,"\u0441\u0432\u043e\u0457":1,"\u0441\u043a\u0430\u043d\u0435\u0440\u0438":1,"\u0441\u043f\u0440\u0430\u0432\u0434\u0456":1,"\u0441\u0442\u0430\u043d\u0443":1,"\u0441\u0442\u0430\u0440\u0442":5,"\u0442\u0430\u043a\u0435":1,"\u0442\u0456\u043b\u044c\u043a\u0438":7,"\u0443":1,"\u0443\u043f\u043e\u0434\u043e\u0431\u0430\u043d\u043d\u044f":4,"\u0444\u0430\u0439\u043b":1,"\u0444\u0430\u0439\u043b\u0438":1,"\u0444\u0456\u043b\u044c\u0442\u0440\u0430\u0446\u0456\u044f":7,"\u0445\u043e\u0447\u0443":1,"\u0446\u0435":1,"\u0447\u0430\u0441\u0442\u0456":1,"\u0447\u043e\u043c\u0443":1,"\u0448\u0432\u0438\u0434\u043a\u0438\u0439":5,"\u0449\u043e":1,"\u0449\u043e\u0431":1,"\u044f":1,"\u044f\u043a\u043e\u0457":1,"\u044f\u043a\u0456":1,"\u0454":1,"\u0456":7,"\u0456\u043d\u0448\u0456":1,appnam:[],changelog:0,dupeguru:[1,3],help:3,indic:3,tabl:3}}) \ No newline at end of file