From ed9270e2825e6d19636184ee4863ec0f184bf753 Mon Sep 17 00:00:00 2001 From: "dr.hualinxiao@gmail.com" Date: Thu, 31 Mar 2022 10:16:54 +0200 Subject: [PATCH] added documentation --- docs/Makefile | 20 - docs/build/doctrees/environment.pickle | Bin 28684 -> 0 bytes docs/build/doctrees/index.doctree | Bin 4935 -> 0 bytes docs/build/doctrees/modules.doctree | Bin 2646 -> 0 bytes docs/build/doctrees/stixdcpy.doctree | Bin 93993 -> 0 bytes docs/build/html/.buildinfo | 4 - docs/build/html/_sources/index.rst.txt | 24 - docs/build/html/_sources/modules.rst.txt | 7 - docs/build/html/_sources/stixdcpy.rst.txt | 85 - docs/build/html/_static/alabaster.css | 701 - docs/build/html/_static/basic.css | 904 -- docs/build/html/_static/custom.css | 1 - docs/build/html/_static/doctools.js | 323 - .../html/_static/documentation_options.js | 12 - docs/build/html/_static/file.png | Bin 286 -> 0 bytes docs/build/html/_static/jquery-3.5.1.js | 10872 ---------------- docs/build/html/_static/jquery.js | 2 - docs/build/html/_static/language_data.js | 297 - docs/build/html/_static/minus.png | Bin 90 -> 0 bytes docs/build/html/_static/plus.png | Bin 90 -> 0 bytes docs/build/html/_static/pygments.css | 82 - docs/build/html/_static/searchtools.js | 522 - docs/build/html/_static/underscore-1.13.1.js | 2042 --- docs/build/html/_static/underscore.js | 6 - docs/build/html/genindex.html | 409 - docs/build/html/index.html | 124 - docs/build/html/modules.html | 130 - docs/build/html/objects.inv | Bin 770 -> 0 bytes docs/build/html/py-modindex.html | 154 - docs/build/html/search.html | 122 - docs/build/html/searchindex.js | 1 - docs/build/html/stixdcpy.html | 441 - docs/make.bat | 35 - docs/source/conf.py | 56 - docs/source/index.rst | 24 - docs/source/modules.rst | 7 - docs/source/stixdcpy.rst | 85 - docs/stixdcpy/ancillary.html | 693 + docs/stixdcpy/cfl.html | 53 + docs/stixdcpy/correction.html | 645 + docs/stixdcpy/detector_view.html | 877 ++ docs/stixdcpy/energylut.html | 569 + docs/stixdcpy/housekeeping.html | 362 + docs/stixdcpy/index.html | 144 + docs/stixdcpy/instrument.html | 1673 +++ docs/stixdcpy/io.html | 287 + docs/stixdcpy/logger.html | 61 + docs/stixdcpy/net.html | 1509 +++ docs/stixdcpy/quicklook.html | 452 + docs/stixdcpy/science.html | 1577 +++ docs/stixdcpy/time.html | 310 + docs/stixdcpy/transmission.html | 1066 ++ docs/stixdcpy/transmission_backup.html | 1067 ++ ...509T042711-20210509T044405_010270_V01.fits | Bin 0 -> 10071360 bytes stixdcpy/correction.py | 2 +- 55 files changed, 11346 insertions(+), 17493 deletions(-) delete mode 100755 docs/Makefile delete mode 100755 docs/build/doctrees/environment.pickle delete mode 100755 docs/build/doctrees/index.doctree delete mode 100755 docs/build/doctrees/modules.doctree delete mode 100755 docs/build/doctrees/stixdcpy.doctree delete mode 100755 docs/build/html/.buildinfo delete mode 100755 docs/build/html/_sources/index.rst.txt delete mode 100755 docs/build/html/_sources/modules.rst.txt delete mode 100755 docs/build/html/_sources/stixdcpy.rst.txt delete mode 100755 docs/build/html/_static/alabaster.css delete mode 100755 docs/build/html/_static/basic.css delete mode 100755 docs/build/html/_static/custom.css delete mode 100755 docs/build/html/_static/doctools.js delete mode 100755 docs/build/html/_static/documentation_options.js delete mode 100755 docs/build/html/_static/file.png delete mode 100755 docs/build/html/_static/jquery-3.5.1.js delete mode 100755 docs/build/html/_static/jquery.js delete mode 100755 docs/build/html/_static/language_data.js delete mode 100755 docs/build/html/_static/minus.png delete mode 100755 docs/build/html/_static/plus.png delete mode 100755 docs/build/html/_static/pygments.css delete mode 100755 docs/build/html/_static/searchtools.js delete mode 100755 docs/build/html/_static/underscore-1.13.1.js delete mode 100755 docs/build/html/_static/underscore.js delete mode 100755 docs/build/html/genindex.html delete mode 100755 docs/build/html/index.html delete mode 100755 docs/build/html/modules.html delete mode 100755 docs/build/html/objects.inv delete mode 100755 docs/build/html/py-modindex.html delete mode 100755 docs/build/html/search.html delete mode 100755 docs/build/html/searchindex.js delete mode 100755 docs/build/html/stixdcpy.html delete mode 100755 docs/make.bat delete mode 100755 docs/source/conf.py delete mode 100755 docs/source/index.rst delete mode 100755 docs/source/modules.rst delete mode 100755 docs/source/stixdcpy.rst create mode 100644 docs/stixdcpy/ancillary.html create mode 100644 docs/stixdcpy/cfl.html create mode 100644 docs/stixdcpy/correction.html create mode 100644 docs/stixdcpy/detector_view.html create mode 100644 docs/stixdcpy/energylut.html create mode 100644 docs/stixdcpy/housekeeping.html create mode 100644 docs/stixdcpy/index.html create mode 100644 docs/stixdcpy/instrument.html create mode 100644 docs/stixdcpy/io.html create mode 100644 docs/stixdcpy/logger.html create mode 100644 docs/stixdcpy/net.html create mode 100644 docs/stixdcpy/quicklook.html create mode 100644 docs/stixdcpy/science.html create mode 100644 docs/stixdcpy/time.html create mode 100644 docs/stixdcpy/transmission.html create mode 100644 docs/stixdcpy/transmission_backup.html create mode 100755 downloads/solo_L1A_stix-sci-xray-l1-2105090003_20210509T042711-20210509T044405_010270_V01.fits diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100755 index d0c3cbf..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/build/doctrees/environment.pickle b/docs/build/doctrees/environment.pickle deleted file mode 100755 index 7e285ce367a86d5ba1efeeacec379e4c07654a2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28684 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 RUx#`tuGX%SRVItI{|7bnwAugw diff --git a/docs/build/doctrees/index.doctree b/docs/build/doctrees/index.doctree deleted file mode 100755 index 9a157e587b2fed0992588a94445b6949b0bf0ac3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4935 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 diff --git a/docs/build/doctrees/stixdcpy.doctree b/docs/build/doctrees/stixdcpy.doctree deleted file mode 100755 index 06cc54be91d06e88779196eb82571f3708241ea9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 93993 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 diff --git a/docs/build/html/.buildinfo b/docs/build/html/.buildinfo deleted file mode 100755 index 490f5bb..0000000 --- a/docs/build/html/.buildinfo +++ /dev/null @@ -1,4 +0,0 @@ -# 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: 152a61ac7f0bfd22839bd3529f82a2ad -tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/build/html/_sources/index.rst.txt b/docs/build/html/_sources/index.rst.txt deleted file mode 100755 index f1c3472..0000000 --- a/docs/build/html/_sources/index.rst.txt +++ /dev/null @@ -1,24 +0,0 @@ -.. stixdcpy documentation master file, created by - sphinx-quickstart on Tue Sep 7 13:51:38 2021. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to stixdcpy's documentation! -==================================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - modules - - - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/build/html/_sources/modules.rst.txt b/docs/build/html/_sources/modules.rst.txt deleted file mode 100755 index 9d3c49b..0000000 --- a/docs/build/html/_sources/modules.rst.txt +++ /dev/null @@ -1,7 +0,0 @@ -stixdcpy -======== - -.. toctree:: - :maxdepth: 4 - - stixdcpy diff --git a/docs/build/html/_sources/stixdcpy.rst.txt b/docs/build/html/_sources/stixdcpy.rst.txt deleted file mode 100755 index f6d07bb..0000000 --- a/docs/build/html/_sources/stixdcpy.rst.txt +++ /dev/null @@ -1,85 +0,0 @@ -stixdcpy package -================ - -Submodules ----------- - -stixdcpy.ancillarydata module ------------------------------ - -.. automodule:: stixdcpy.ancillarydata - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.energylut module -------------------------- - -.. automodule:: stixdcpy.energylut - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.housekeeping module ----------------------------- - -.. automodule:: stixdcpy.housekeeping - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.io module ------------------- - -.. automodule:: stixdcpy.io - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.net module -------------------- - -.. automodule:: stixdcpy.net - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.quicklook module -------------------------- - -.. automodule:: stixdcpy.quicklook - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.sci\_l1\_corrections module ------------------------------------- - -.. automodule:: stixdcpy.sci_l1_corrections - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.sciencedata module ---------------------------- - -.. automodule:: stixdcpy.sciencedata - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.time module --------------------- - -.. automodule:: stixdcpy.time - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: stixdcpy - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/build/html/_static/alabaster.css b/docs/build/html/_static/alabaster.css deleted file mode 100755 index 0eddaeb..0000000 --- a/docs/build/html/_static/alabaster.css +++ /dev/null @@ -1,701 +0,0 @@ -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: Georgia, serif; - font-size: 17px; - background-color: #fff; - color: #000; - margin: 0; - padding: 0; -} - - -div.document { - width: 940px; - margin: 30px auto 0 auto; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 220px; -} - -div.sphinxsidebar { - width: 220px; - font-size: 14px; - line-height: 1.5; -} - -hr { - border: 1px solid #B1B4B6; -} - -div.body { - background-color: #fff; - color: #3E4349; - padding: 0 30px 0 30px; -} - -div.body > .section { - text-align: left; -} - -div.footer { - width: 940px; - margin: 20px auto 30px auto; - font-size: 14px; - color: #888; - text-align: right; -} - -div.footer a { - color: #888; -} - -p.caption { - font-family: inherit; - font-size: inherit; -} - - -div.relations { - display: none; -} - - -div.sphinxsidebar a { - color: #444; - text-decoration: none; - border-bottom: 1px dotted #999; -} - -div.sphinxsidebar a:hover { - border-bottom: 1px solid #999; -} - -div.sphinxsidebarwrapper { - padding: 18px 10px; -} - -div.sphinxsidebarwrapper p.logo { - padding: 0; - margin: -10px 0 0 0px; - text-align: center; -} - -div.sphinxsidebarwrapper h1.logo { - margin-top: -10px; - text-align: center; - margin-bottom: 5px; - text-align: left; -} - -div.sphinxsidebarwrapper h1.logo-name { - margin-top: 0px; -} - -div.sphinxsidebarwrapper p.blurb { - margin-top: 0; - font-style: normal; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - font-family: Georgia, serif; - color: #444; - font-size: 24px; - font-weight: normal; - margin: 0 0 5px 0; - padding: 0; -} - -div.sphinxsidebar h4 { - font-size: 20px; -} - -div.sphinxsidebar h3 a { - color: #444; -} - -div.sphinxsidebar p.logo a, -div.sphinxsidebar h3 a, -div.sphinxsidebar p.logo a:hover, -div.sphinxsidebar h3 a:hover { - border: none; -} - -div.sphinxsidebar p { - color: #555; - margin: 10px 0; -} - -div.sphinxsidebar ul { - margin: 10px 0; - padding: 0; - color: #000; -} - -div.sphinxsidebar ul li.toctree-l1 > a { - font-size: 120%; -} - -div.sphinxsidebar ul li.toctree-l2 > a { - font-size: 110%; -} - -div.sphinxsidebar input { - border: 1px solid #CCC; - font-family: Georgia, serif; - font-size: 1em; -} - -div.sphinxsidebar hr { - border: none; - height: 1px; - color: #AAA; - background: #AAA; - - text-align: left; - margin-left: 0; - width: 50%; -} - -div.sphinxsidebar .badge { - border-bottom: none; -} - -div.sphinxsidebar .badge:hover { - border-bottom: none; -} - -/* To address an issue with donation coming after search */ -div.sphinxsidebar h3.donation { - margin-top: 10px; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: #004B6B; - text-decoration: underline; -} - -a:hover { - color: #6D4100; - text-decoration: underline; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: Georgia, serif; - font-weight: normal; - margin: 30px 0px 10px 0px; - padding: 0; -} - -div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } -div.body h2 { font-size: 180%; } -div.body h3 { font-size: 150%; } -div.body h4 { font-size: 130%; } -div.body h5 { font-size: 100%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: #DDD; - padding: 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - color: #444; - background: #EAEAEA; -} - -div.body p, div.body dd, div.body li { - line-height: 1.4em; -} - -div.admonition { - margin: 20px 0px; - padding: 10px 30px; - background-color: #EEE; - border: 1px solid #CCC; -} - -div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { - background-color: #FBFBFB; - border-bottom: 1px solid #fafafa; -} - -div.admonition p.admonition-title { - font-family: Georgia, serif; - font-weight: normal; - font-size: 24px; - margin: 0 0 10px 0; - padding: 0; - line-height: 1; -} - -div.admonition p.last { - margin-bottom: 0; -} - -div.highlight { - background-color: #fff; -} - -dt:target, .highlight { - background: #FAF3E8; -} - -div.warning { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.danger { - background-color: #FCC; - border: 1px solid #FAA; - -moz-box-shadow: 2px 2px 4px #D52C2C; - -webkit-box-shadow: 2px 2px 4px #D52C2C; - box-shadow: 2px 2px 4px #D52C2C; -} - -div.error { - background-color: #FCC; - border: 1px solid #FAA; - -moz-box-shadow: 2px 2px 4px #D52C2C; - -webkit-box-shadow: 2px 2px 4px #D52C2C; - box-shadow: 2px 2px 4px #D52C2C; -} - -div.caution { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.attention { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.important { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.note { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.tip { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.hint { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.seealso { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.topic { - background-color: #EEE; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre, tt, code { - font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.9em; -} - -.hll { - background-color: #FFC; - margin: 0 -12px; - padding: 0 12px; - display: block; -} - -img.screenshot { -} - -tt.descname, tt.descclassname, code.descname, code.descclassname { - font-size: 0.95em; -} - -tt.descname, code.descname { - padding-right: 0.08em; -} - -img.screenshot { - -moz-box-shadow: 2px 2px 4px #EEE; - -webkit-box-shadow: 2px 2px 4px #EEE; - box-shadow: 2px 2px 4px #EEE; -} - -table.docutils { - border: 1px solid #888; - -moz-box-shadow: 2px 2px 4px #EEE; - -webkit-box-shadow: 2px 2px 4px #EEE; - box-shadow: 2px 2px 4px #EEE; -} - -table.docutils td, table.docutils th { - border: 1px solid #888; - padding: 0.25em 0.7em; -} - -table.field-list, table.footnote { - border: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - -table.footnote { - margin: 15px 0; - width: 100%; - border: 1px solid #EEE; - background: #FDFDFD; - font-size: 0.9em; -} - -table.footnote + table.footnote { - margin-top: -15px; - border-top: none; -} - -table.field-list th { - padding: 0 0.8em 0 0; -} - -table.field-list td { - padding: 0; -} - -table.field-list p { - margin-bottom: 0.8em; -} - -/* Cloned from - * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 - */ -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -table.footnote td.label { - width: .1px; - padding: 0.3em 0 0.3em 0.5em; -} - -table.footnote td { - padding: 0.3em 0.5em; -} - -dl { - margin: 0; - padding: 0; -} - -dl dd { - margin-left: 30px; -} - -blockquote { - margin: 0 0 0 30px; - padding: 0; -} - -ul, ol { - /* Matches the 30px from the narrow-screen "li > ul" selector below */ - margin: 10px 0 10px 30px; - padding: 0; -} - -pre { - background: #EEE; - padding: 7px 30px; - margin: 15px 0px; - line-height: 1.3em; -} - -div.viewcode-block:target { - background: #ffd; -} - -dl pre, blockquote pre, li pre { - margin-left: 0; - padding-left: 30px; -} - -tt, code { - background-color: #ecf0f3; - color: #222; - /* padding: 1px 2px; */ -} - -tt.xref, code.xref, a tt { - background-color: #FBFBFB; - border-bottom: 1px solid #fff; -} - -a.reference { - text-decoration: none; - border-bottom: 1px dotted #004B6B; -} - -/* Don't put an underline on images */ -a.image-reference, a.image-reference:hover { - border-bottom: none; -} - -a.reference:hover { - border-bottom: 1px solid #6D4100; -} - -a.footnote-reference { - text-decoration: none; - font-size: 0.7em; - vertical-align: top; - border-bottom: 1px dotted #004B6B; -} - -a.footnote-reference:hover { - border-bottom: 1px solid #6D4100; -} - -a:hover tt, a:hover code { - background: #EEE; -} - - -@media screen and (max-width: 870px) { - - div.sphinxsidebar { - display: none; - } - - div.document { - width: 100%; - - } - - div.documentwrapper { - margin-left: 0; - margin-top: 0; - margin-right: 0; - margin-bottom: 0; - } - - div.bodywrapper { - margin-top: 0; - margin-right: 0; - margin-bottom: 0; - margin-left: 0; - } - - ul { - margin-left: 0; - } - - li > ul { - /* Matches the 30px from the "ul, ol" selector above */ - margin-left: 30px; - } - - .document { - width: auto; - } - - .footer { - width: auto; - } - - .bodywrapper { - margin: 0; - } - - .footer { - width: auto; - } - - .github { - display: none; - } - - - -} - - - -@media screen and (max-width: 875px) { - - body { - margin: 0; - padding: 20px 30px; - } - - div.documentwrapper { - float: none; - background: #fff; - } - - div.sphinxsidebar { - display: block; - float: none; - width: 102.5%; - margin: 50px -30px -20px -30px; - padding: 10px 20px; - background: #333; - color: #FFF; - } - - div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, - div.sphinxsidebar h3 a { - color: #fff; - } - - div.sphinxsidebar a { - color: #AAA; - } - - div.sphinxsidebar p.logo { - display: none; - } - - div.document { - width: 100%; - margin: 0; - } - - div.footer { - display: none; - } - - div.bodywrapper { - margin: 0; - } - - div.body { - min-height: 0; - padding: 0; - } - - .rtd_doc_footer { - display: none; - } - - .document { - width: auto; - } - - .footer { - width: auto; - } - - .footer { - width: auto; - } - - .github { - display: none; - } -} - - -/* misc. */ - -.revsys-inline { - display: none!important; -} - -/* Make nested-list/multi-paragraph items look better in Releases changelog - * pages. Without this, docutils' magical list fuckery causes inconsistent - * formatting between different release sub-lists. - */ -div#changelog > div.section > ul > li > p:only-child { - margin-bottom: 0; -} - -/* Hide fugly table cell borders in ..bibliography:: directive output */ -table.docutils.citation, table.docutils.citation td, table.docutils.citation th { - border: none; - /* Below needed in some edge cases; if not applied, bottom shadows appear */ - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - - -/* relbar */ - -.related { - line-height: 30px; - width: 100%; - font-size: 0.9rem; -} - -.related.top { - border-bottom: 1px solid #EEE; - margin-bottom: 20px; -} - -.related.bottom { - border-top: 1px solid #EEE; -} - -.related ul { - padding: 0; - margin: 0; - list-style: none; -} - -.related li { - display: inline; -} - -nav#rellinks { - float: right; -} - -nav#rellinks li+li:before { - content: "|"; -} - -nav#breadcrumbs li+li:before { - content: "\00BB"; -} - -/* Hide certain items when printing */ -@media print { - div.related { - display: none; - } -} \ No newline at end of file diff --git a/docs/build/html/_static/basic.css b/docs/build/html/_static/basic.css deleted file mode 100755 index 912859b..0000000 --- a/docs/build/html/_static/basic.css +++ /dev/null @@ -1,904 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -div.section::after { - display: block; - content: ''; - clear: left; -} - -/* -- 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 form.search { - overflow: hidden; -} - -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 p.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: 450px; - max-width: 800px; -} - -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; -} - -a.brackets:before, -span.brackets > a:before{ - content: "["; -} - -a.brackets:after, -span.brackets > a:after { - content: "]"; -} - -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, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, figure.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, figure.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -img.align-default, figure.align-default, .figure.align-default { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-default { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar, -aside.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px; - background-color: #ffe; - width: 40%; - float: right; - clear: right; - overflow-x: auto; -} - -p.sidebar-title { - font-weight: bold; -} - -div.admonition, div.topic, blockquote { - clear: left; -} - -/* -- topics ---------------------------------------------------------------- */ - -div.topic { - border: 1px solid #ccc; - padding: 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; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- content of sidebars/topics/admonitions -------------------------------- */ - -div.sidebar > :last-child, -aside.sidebar > :last-child, -div.topic > :last-child, -div.admonition > :last-child { - margin-bottom: 0; -} - -div.sidebar::after, -aside.sidebar::after, -div.topic::after, -div.admonition::after, -blockquote::after { - display: block; - content: ''; - clear: both; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - margin-top: 10px; - margin-bottom: 10px; - border: 0; - border-collapse: collapse; -} - -table.align-center { - margin-left: auto; - margin-right: auto; -} - -table.align-default { - 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; -} - -th > :first-child, -td > :first-child { - margin-top: 0px; -} - -th > :last-child, -td > :last-child { - margin-bottom: 0px; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure, figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption, figcaption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number, -figcaption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text, -figcaption 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; -} - -/* -- hlist styles ---------------------------------------------------------- */ - -table.hlist { - margin: 1em 0; -} - -table.hlist td { - vertical-align: top; -} - -/* -- object description styles --------------------------------------------- */ - -.sig { - font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; -} - -.sig-name, code.descname { - background-color: transparent; - font-weight: bold; -} - -.sig-name { - font-size: 1.1em; -} - -code.descname { - font-size: 1.2em; -} - -.sig-prename, code.descclassname { - background-color: transparent; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.sig-param.n { - font-style: italic; -} - -/* C++ specific styling */ - -.sig-inline.c-texpr, -.sig-inline.cpp-texpr { - font-family: unset; -} - -.sig.c .k, .sig.c .kt, -.sig.cpp .k, .sig.cpp .kt { - color: #0033B3; -} - -.sig.c .m, -.sig.cpp .m { - color: #1750EB; -} - -.sig.c .s, .sig.c .sc, -.sig.cpp .s, .sig.cpp .sc { - color: #067D17; -} - - -/* -- 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; -} - -:not(li) > ol > li:first-child > :first-child, -:not(li) > ul > li:first-child > :first-child { - margin-top: 0px; -} - -:not(li) > ol > li:last-child > :last-child, -:not(li) > ul > li:last-child > :last-child { - margin-bottom: 0px; -} - -ol.simple ol p, -ol.simple ul p, -ul.simple ol p, -ul.simple ul p { - margin-top: 0; -} - -ol.simple > li:not(:first-child) > p, -ul.simple > li:not(:first-child) > p { - margin-top: 0; -} - -ol.simple p, -ul.simple p { - margin-bottom: 0; -} - -dl.footnote > dt, -dl.citation > dt { - float: left; - margin-right: 0.5em; -} - -dl.footnote > dd, -dl.citation > dd { - margin-bottom: 0em; -} - -dl.footnote > dd:after, -dl.citation > dd:after { - content: ""; - clear: both; -} - -dl.field-list { - display: grid; - grid-template-columns: fit-content(30%) auto; -} - -dl.field-list > dt { - font-weight: bold; - word-break: break-word; - padding-left: 0.5em; - padding-right: 5px; -} - -dl.field-list > dt:after { - content: ":"; -} - -dl.field-list > dd { - padding-left: 0.5em; - margin-top: 0em; - margin-left: 0em; - margin-bottom: 0em; -} - -dl { - margin-bottom: 15px; -} - -dd > :first-child { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dl > dd:last-child, -dl > dd:last-child > :last-child { - margin-bottom: 0; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.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; -} - -.classifier:before { - font-style: normal; - margin: 0.5em; - content: ":"; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -pre, div[class*="highlight-"] { - clear: both; -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; -} - -div[class*="highlight-"] { - margin: 1em 0; -} - -td.linenos pre { - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - display: block; -} - -table.highlighttable tbody { - display: block; -} - -table.highlighttable tr { - display: flex; -} - -table.highlighttable td { - margin: 0; - padding: 0; -} - -table.highlighttable td.linenos { - padding-right: 0.5em; -} - -table.highlighttable td.code { - flex: 1; - overflow: hidden; -} - -.highlight .hll { - display: block; -} - -div.highlight pre, -table.highlighttable pre { - margin: 0; -} - -div.code-block-caption + div { - margin-top: 0; -} - -div.code-block-caption { - margin-top: 1em; - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -table.highlighttable td.linenos, -span.linenos, -div.highlight span.gp { /* gp: Generic.Prompt */ - user-select: none; - -webkit-user-select: text; /* Safari fallback only */ - -webkit-user-select: none; /* Chrome/Safari */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* IE10+ */ -} - -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 { - margin: 1em 0; -} - -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: absolute; - 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/docs/build/html/_static/custom.css b/docs/build/html/_static/custom.css deleted file mode 100755 index 2a924f1..0000000 --- a/docs/build/html/_static/custom.css +++ /dev/null @@ -1 +0,0 @@ -/* This file intentionally left blank. */ diff --git a/docs/build/html/_static/doctools.js b/docs/build/html/_static/doctools.js deleted file mode 100755 index 8cbf1b1..0000000 --- a/docs/build/html/_static/doctools.js +++ /dev/null @@ -1,323 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Sphinx JavaScript utilities for all documentation. - * - * :copyright: Copyright 2007-2021 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 - * - * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL - */ -jQuery.urldecode = function(x) { - if (!x) { - return 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) && - !jQuery(node.parentNode).hasClass("nohighlight")) { - 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 rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); - var bbox = node.parentElement.getBBox(); - 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); - 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(); - if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { - this.initOnKeyListeners(); - } - }, - - /** - * 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).keydown(function(event) { - var activeElementType = document.activeElement.tagName; - // don't navigate when in search box, textarea, dropdown or button - if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' - && activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey - && !event.shiftKey) { - switch (event.keyCode) { - case 37: // left - var prevHref = $('link[rel="prev"]').prop('href'); - if (prevHref) { - window.location.href = prevHref; - return false; - } - break; - case 39: // right - var nextHref = $('link[rel="next"]').prop('href'); - if (nextHref) { - window.location.href = nextHref; - return false; - } - break; - } - } - }); - } -}; - -// quick alias for translations -_ = Documentation.gettext; - -$(document).ready(function() { - Documentation.init(); -}); diff --git a/docs/build/html/_static/documentation_options.js b/docs/build/html/_static/documentation_options.js deleted file mode 100755 index 07966ec..0000000 --- a/docs/build/html/_static/documentation_options.js +++ /dev/null @@ -1,12 +0,0 @@ -var DOCUMENTATION_OPTIONS = { - URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '1.0', - LANGUAGE: 'None', - COLLAPSE_INDEX: false, - BUILDER: 'html', - FILE_SUFFIX: '.html', - LINK_SUFFIX: '.html', - HAS_SOURCE: true, - SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: false -}; \ No newline at end of file diff --git a/docs/build/html/_static/file.png b/docs/build/html/_static/file.png deleted file mode 100755 index a858a410e4faa62ce324d814e4b816fff83a6fb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( diff --git a/docs/build/html/_static/jquery-3.5.1.js b/docs/build/html/_static/jquery-3.5.1.js deleted file mode 100755 index 5093733..0000000 --- a/docs/build/html/_static/jquery-3.5.1.js +++ /dev/null @@ -1,10872 +0,0 @@ -/*! - * jQuery JavaScript Library v3.5.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: 2020-05-04T22:49Z - */ -( 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 getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var flat = arr.flat ? function( array ) { - return arr.flat.call( array ); -} : function( array ) { - return arr.concat.apply( [], array ); -}; - - -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 = {}; - -var isFunction = function isFunction( obj ) { - - // Support: Chrome <=57, Firefox <=52 - // In some browsers, typeof returns "function" for HTML elements - // (i.e., `typeof document.createElement( "object" ) === "function"`). - // We don't want to classify *any* DOM node as a function. - return typeof obj === "function" && typeof obj.nodeType !== "number"; - }; - - -var isWindow = function isWindow( obj ) { - return obj != null && obj === obj.window; - }; - - -var document = window.document; - - - - var preservedScriptAttributes = { - type: true, - src: true, - nonce: true, - noModule: true - }; - - function DOMEval( code, node, doc ) { - doc = doc || document; - - var i, val, - script = doc.createElement( "script" ); - - script.text = code; - if ( node ) { - for ( i in preservedScriptAttributes ) { - - // Support: Firefox 64+, Edge 18+ - // Some browsers don't support the "nonce" property on scripts. - // On the other hand, just using `getAttribute` is not enough as - // the `nonce` attribute is reset to an empty string whenever it - // becomes browsing-context connected. - // See https://github.com/whatwg/html/issues/2369 - // See https://html.spec.whatwg.org/#nonce-attributes - // The `node.getAttribute` check was added for the sake of - // `jQuery.globalEval` so that it can fake a nonce-containing node - // via an object. - val = node[ i ] || node.getAttribute && node.getAttribute( i ); - if ( val ) { - script.setAttribute( i, val ); - } - } - } - doc.head.appendChild( script ).parentNode.removeChild( script ); - } - - -function toType( 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; -} -/* 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.5.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 ); - }; - -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 ); - }, - - even: function() { - return this.pushStack( jQuery.grep( this, function( _elem, i ) { - return ( i + 1 ) % 2; - } ) ); - }, - - odd: function() { - return this.pushStack( jQuery.grep( this, function( _elem, i ) { - return i % 2; - } ) ); - }, - - 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" && !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 ) { - copy = options[ name ]; - - // Prevent Object.prototype pollution - // Prevent never-ending loop - if ( name === "__proto__" || target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = Array.isArray( copy ) ) ) ) { - src = target[ name ]; - - // Ensure proper type for the source value - if ( copyIsArray && !Array.isArray( src ) ) { - clone = []; - } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { - clone = {}; - } else { - clone = src; - } - copyIsArray = false; - - // 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() {}, - - 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 ) { - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - // Evaluates a script in a provided context; falls back to the global one - // if not specified. - globalEval: function( code, options, doc ) { - DOMEval( code, { nonce: options && options.nonce }, doc ); - }, - - 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; - }, - - // 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 flat( ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // 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 = toType( obj ); - - if ( isFunction( obj ) || 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.5 - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://js.foundation/ - * - * Date: 2020-03-14 - */ -( 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(), - nonnativeSelectorCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // Instance methods - hasOwn = ( {} ).hasOwnProperty, - arr = [], - pop = arr.pop, - pushNative = 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]", - - // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram - identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + - "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", - - // 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 + - "*" ), - rdescend = new RegExp( whitespace + "|>" ), - - 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" ) - }, - - rhtml = /HTML$/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-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), - funescape = function( escape, nonHex ) { - var high = "0x" + escape.slice( 1 ) - 0x10000; - - return nonHex ? - - // Strip the backslash prefix from a non-hex escape sequence - nonHex : - - // Replace a hexadecimal escape sequence with the encoded Unicode code point - // Support: IE <=11+ - // For values outside the Basic Multilingual Plane (BMP), manually construct a - // surrogate pair - high < 0 ? - String.fromCharCode( high + 0x10000 ) : - 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(); - }, - - inDisabledFieldset = addCombinator( - function( elem ) { - return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; - }, - { 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 - // eslint-disable-next-line no-unused-expressions - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - pushNative.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 ) { - 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 && - !nonnativeSelectorCache[ selector + " " ] && - ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && - - // Support: IE 8 only - // Exclude object elements - ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { - - newSelector = selector; - newContext = context; - - // qSA considers elements outside a scoping root when evaluating child or - // descendant combinators, which is not what we want. - // In such cases, we work around the behavior by prefixing every selector in the - // list with an ID selector referencing the scope context. - // The technique has to be used as well when a leading combinator is used - // as such selectors are not recognized by querySelectorAll. - // Thanks to Andrew Dupont for this technique. - if ( nodeType === 1 && - ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - - // We can use :scope instead of the ID hack if the browser - // supports it & if we're not changing the context. - if ( newContext !== context || !support.scope ) { - - // 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 ? "#" + nid : ":scope" ) + " " + - toSelector( groups[ i ] ); - } - newSelector = groups.join( "," ); - } - - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - nonnativeSelectorCache( selector, true ); - } 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 && - inDisabledFieldset( 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 ) { - var namespace = elem.namespaceURI, - docElem = ( elem.ownerDocument || elem ).documentElement; - - // Support: IE <=8 - // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes - // https://bugs.jquery.com/ticket/4833 - return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); -}; - -/** - * 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 - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - 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 12 - 18+ - // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - 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 ); - } - } - - // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, - // Safari 4 - 5 only, Opera <=11.6 - 12.x only - // IE/Edge & older browsers don't support the :scope pseudo-class. - // Support: Safari 6.0 only - // Safari 6.0 supports :scope but it's an alias of :root there. - support.scope = assert( function( el ) { - docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); - return typeof el.querySelectorAll !== "undefined" && - !el.querySelectorAll( ":scope fieldset div" ).length; - } ); - - /* 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 ) { - - var input; - - // 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( "~=" ); - } - - // Support: IE 11+, Edge 15 - 18+ - // IE 11/Edge don't find elements on a `[name='']` query in some cases. - // Adding a temporary attribute to the document before the selection works - // around the issue. - // Interestingly, IE 10 & older don't seem to have the issue. - input = document.createElement( "input" ); - input.setAttribute( "name", "" ); - el.appendChild( input ); - if ( !el.querySelectorAll( "[name='']" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + - whitespace + "*(?:''|\"\")" ); - } - - // 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( ".#.+[+~]" ); - } - - // Support: Firefox <=3.6 - 5 only - // Old Firefox doesn't throw on a badly-escaped identifier. - el.querySelectorAll( "\\\f" ); - rbuggyQSA.push( "[\\r\\n\\f]" ); - } ); - - 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" ); - } - - // Support: Opera 10 - 11 only - // 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 - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - 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 - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( a == document || a.ownerDocument == preferredDoc && - contains( preferredDoc, a ) ) { - return -1; - } - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - 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 ) { - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - /* eslint-disable eqeqeq */ - return a == document ? -1 : - b == document ? 1 : - /* eslint-enable eqeqeq */ - 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 - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - /* eslint-disable eqeqeq */ - ap[ i ] == preferredDoc ? -1 : - bp[ i ] == preferredDoc ? 1 : - /* eslint-enable eqeqeq */ - 0; - }; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - setDocument( elem ); - - if ( support.matchesSelector && documentIsHTML && - !nonnativeSelectorCache[ 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 ) { - nonnativeSelectorCache( expr, true ); - } - } - - return Sizzle( expr, document, null, [ elem ] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - - // Set document vars if needed - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( ( context.ownerDocument || context ) != document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - - // Set document vars if needed - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - 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 += ""; - - /* eslint-disable max-len */ - - 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; - /* eslint-enable max-len */ - - }; - }, - - "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 || 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 ) { - // eslint-disable-next-line no-unused-expressions - 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 > length ? - 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 ) { - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - 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; - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - 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 ); - - - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( 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; - } ); - } - - // Filtered directly for both simple and complex selectors - return jQuery.filter( qualifier, elements, not ); -} - -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 ( 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 ( 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 ( elem.contentDocument != null && - - // Support: IE 11+ - // elements with no `data` attribute has an object - // `contentDocument` with a `null` prototype. - getProto( elem.contentDocument ) ) { - - 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 ( isFunction( arg ) ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && toType( 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 && isFunction( ( method = value.promise ) ) ) { - method.call( value ).done( resolve ).fail( reject ); - - // Other thenables - } else if ( value && 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 = 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 && 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 ( 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, - isFunction( onProgress ) ? - onProgress : - Identity, - newDefer.notifyWith - ) - ); - - // fulfilled_handlers.add( ... ) - tuples[ 1 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onFulfilled ) ? - onFulfilled : - Identity - ) - ); - - // rejected_handlers.add( ... ) - tuples[ 2 ][ 3 ].add( - resolve( - 0, - newDefer, - 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, - - // rejected_handlers.disable - // fulfilled_handlers.disable - tuples[ 3 - i ][ 3 ].disable, - - // progress_callbacks.lock - tuples[ 0 ][ 2 ].lock, - - // progress_handlers.lock - tuples[ 0 ][ 3 ].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" || - 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 ( toType( 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 ( !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; -}; - - -// Matches dashed string for camelizing -var rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g; - -// Used by camelCase as callback to replace() -function fcamelCase( _all, letter ) { - return letter.toUpperCase(); -} - -// Convert dashed to camelCase; used by the css and data modules -// Support: IE <=9 - 11, Edge 12 - 15 -// Microsoft forgot to hump their vendor prefix (#9572) -function camelCase( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); -} -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[ camelCase( data ) ] = value; - - // Handle: [ owner, { properties } ] args - } else { - - // Copy the properties one-by-one to the cache object - for ( prop in data ) { - cache[ 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 ][ 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( camelCase ); - } else { - key = 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 = 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 documentElement = document.documentElement; - - - - var isAttached = function( elem ) { - return jQuery.contains( elem.ownerDocument, elem ); - }, - composed = { composed: true }; - - // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only - // Check attachment across shadow DOM boundaries when possible (gh-3504) - // Support: iOS 10.0-10.2 only - // Early iOS 10 versions support `attachShadow` but not `getRootNode`, - // leading to errors. We need to check for `getRootNode`. - if ( documentElement.getRootNode ) { - isAttached = function( elem ) { - return jQuery.contains( elem.ownerDocument, elem ) || - elem.getRootNode( composed ) === elem.ownerDocument; - }; - } -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. - isAttached( elem ) && - - jQuery.css( elem, "display" ) === "none"; - }; - - - -function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, scale, - 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 = elem.nodeType && - ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && - rcssNum.exec( jQuery.css( elem, prop ) ); - - if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { - - // Support: Firefox <=54 - // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) - initial = initial / 2; - - // Trust units reported by jQuery.css - unit = unit || initialInUnit[ 3 ]; - - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; - - while ( maxIterations-- ) { - - // Evaluate and update our best guess (doubling guesses that zero out). - // Finish if the scale equals or crosses 1 (making the old*new product non-positive). - jQuery.style( elem, prop, initialInUnit + unit ); - if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { - maxIterations = 0; - } - initialInUnit = initialInUnit / scale; - - } - - initialInUnit = initialInUnit * 2; - jQuery.style( elem, prop, initialInUnit + unit ); - - // Make sure we update the tween properties later on - valueParts = valueParts || []; - } - - 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 = ( /^$|^module$|\/(?:java|ecma)script/i ); - - - -( 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; - - // Support: IE <=9 only - // IE <=9 replaces "; - support.option = !!div.lastChild; -} )(); - - -// We have to close these tags to support XHTML (#13200) -var wrapMap = { - - // 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, "", "" ] -}; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// Support: IE <=9 only -if ( !support.option ) { - wrapMap.optgroup = wrapMap.option = [ 1, "" ]; -} - - -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, attached, 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 ( toType( 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; - } - - attached = isAttached( elem ); - - // Append to fragment - tmp = getAll( fragment.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( attached ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( ( elem = tmp[ j++ ] ) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - return fragment; -} - - -var - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -// Support: IE <=9 - 11+ -// focus() and blur() are asynchronous, except when they are no-op. -// So expect focus to be synchronous when the element is already active, -// and blur to be synchronous when the element is not already active. -// (focus and blur are always synchronous in other supported browsers, -// this just defines when we can count on it). -function expectSync( elem, type ) { - return ( elem === safeActiveElement() ) === ( type === "focus" ); -} - -// Support: IE <=9 only -// Accessing document.activeElement can throw unexpectedly -// https://bugs.jquery.com/ticket/13393 -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 ); - - // Only attach events to objects that accept data - if ( !acceptData( elem ) ) { - 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 = Object.create( null ); - } - 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 ) { - - var i, j, ret, matched, handleObj, handlerQueue, - args = new Array( arguments.length ), - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( nativeEvent ), - - handlers = ( - dataPriv.get( this, "events" ) || Object.create( null ) - )[ 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() ) { - - // If the event is namespaced, then each handler is only invoked if it is - // specially universal or its namespaces are a superset of the event's. - if ( !event.rnamespace || handleObj.namespace === false || - 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: 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 - }, - click: { - - // Utilize native event to ensure correct state for checkable inputs - setup: function( data ) { - - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Claim the first handler - if ( rcheckableType.test( el.type ) && - el.click && nodeName( el, "input" ) ) { - - // dataPriv.set( el, "click", ... ) - leverageNative( el, "click", returnTrue ); - } - - // Return false to allow normal processing in the caller - return false; - }, - trigger: function( data ) { - - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Force setup before triggering a click - if ( rcheckableType.test( el.type ) && - el.click && nodeName( el, "input" ) ) { - - leverageNative( el, "click" ); - } - - // Return non-false to allow normal event-path propagation - return true; - }, - - // For cross-browser consistency, suppress native .click() on links - // Also prevent it if we're currently inside a leveraged native-event stack - _default: function( event ) { - var target = event.target; - return rcheckableType.test( target.type ) && - target.click && nodeName( target, "input" ) && - dataPriv.get( target, "click" ) || - nodeName( 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; - } - } - } - } -}; - -// Ensure the presence of an event listener that handles manually-triggered -// synthetic events by interrupting progress until reinvoked in response to -// *native* events that it fires directly, ensuring that state changes have -// already occurred before other listeners are invoked. -function leverageNative( el, type, expectSync ) { - - // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add - if ( !expectSync ) { - if ( dataPriv.get( el, type ) === undefined ) { - jQuery.event.add( el, type, returnTrue ); - } - return; - } - - // Register the controller as a special universal handler for all event namespaces - dataPriv.set( el, type, false ); - jQuery.event.add( el, type, { - namespace: false, - handler: function( event ) { - var notAsync, result, - saved = dataPriv.get( this, type ); - - if ( ( event.isTrigger & 1 ) && this[ type ] ) { - - // Interrupt processing of the outer synthetic .trigger()ed event - // Saved data should be false in such cases, but might be a leftover capture object - // from an async native handler (gh-4350) - if ( !saved.length ) { - - // Store arguments for use when handling the inner native event - // There will always be at least one argument (an event object), so this array - // will not be confused with a leftover capture object. - saved = slice.call( arguments ); - dataPriv.set( this, type, saved ); - - // Trigger the native event and capture its result - // Support: IE <=9 - 11+ - // focus() and blur() are asynchronous - notAsync = expectSync( this, type ); - this[ type ](); - result = dataPriv.get( this, type ); - if ( saved !== result || notAsync ) { - dataPriv.set( this, type, false ); - } else { - result = {}; - } - if ( saved !== result ) { - - // Cancel the outer synthetic event - event.stopImmediatePropagation(); - event.preventDefault(); - return result.value; - } - - // If this is an inner synthetic event for an event with a bubbling surrogate - // (focus or blur), assume that the surrogate already propagated from triggering the - // native event and prevent that from happening again here. - // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the - // bubbling surrogate propagates *after* the non-bubbling base), but that seems - // less bad than duplication. - } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { - event.stopPropagation(); - } - - // If this is a native event triggered above, everything is now in order - // Fire an inner synthetic event with the original arguments - } else if ( saved.length ) { - - // ...and capture the result - dataPriv.set( this, type, { - value: jQuery.event.trigger( - - // Support: IE <=9 - 11+ - // Extend with the prototype to reset the above stopImmediatePropagation() - jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), - saved.slice( 1 ), - this - ) - } ); - - // Abort handling of the native event - event.stopImmediatePropagation(); - } - } - } ); -} - -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 || Date.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, - code: 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 ); - -jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { - jQuery.event.special[ type ] = { - - // Utilize native event if possible so blur/focus sequence is correct - setup: function() { - - // Claim the first handler - // dataPriv.set( this, "focus", ... ) - // dataPriv.set( this, "blur", ... ) - leverageNative( this, type, expectSync ); - - // Return false to allow normal processing in the caller - return false; - }, - trigger: function() { - - // Force setup before trigger - leverageNative( this, type ); - - // Return non-false to allow normal event-path propagation - return true; - }, - - delegateType: delegateType - }; -} ); - -// 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 - - // Support: IE <=10 - 11, Edge 12 - 13 only - // 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( elem ).children( "tbody" )[ 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 ) { - if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { - elem.type = elem.type.slice( 5 ); - } else { - elem.removeAttribute( "type" ); - } - - return elem; -} - -function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, udataOld, udataCur, events; - - if ( dest.nodeType !== 1 ) { - return; - } - - // 1. Copy private data: events, handlers, etc. - if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.get( src ); - events = pdataOld.events; - - if ( events ) { - dataPriv.remove( dest, "handle 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 = flat( args ); - - var fragment, first, scripts, hasScripts, node, doc, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[ 0 ], - valueIsFunction = isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( valueIsFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return collection.each( function( index ) { - var self = collection.eq( index ); - if ( valueIsFunction ) { - 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 && ( node.type || "" ).toLowerCase() !== "module" ) { - - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl && !node.noModule ) { - jQuery._evalUrl( node.src, { - nonce: node.nonce || node.getAttribute( "nonce" ) - }, doc ); - } - } else { - DOMEval( node.textContent.replace( rcleanScript, "" ), node, 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 && isAttached( node ) ) { - setGlobalEval( getAll( node, "script" ) ); - } - node.parentNode.removeChild( node ); - } - } - - return elem; -} - -jQuery.extend( { - htmlPrefilter: function( html ) { - return html; - }, - - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var i, l, srcElements, destElements, - clone = elem.cloneNode( true ), - inPage = isAttached( 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 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 ); - }; - -var swap = function( elem, options, callback ) { - 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.call( elem ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; -}; - - -var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); - - - -( 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; - } - - container.style.cssText = "position:absolute;left:-11111px;width:60px;" + - "margin-top:1px;padding:0;border:0"; - div.style.cssText = - "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + - "margin:auto;border:1px;padding:1px;" + - "width:60%;top:1%"; - documentElement.appendChild( container ).appendChild( div ); - - var divStyle = window.getComputedStyle( div ); - pixelPositionVal = divStyle.top !== "1%"; - - // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; - - // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 - // Some styles come back with percentage values, even though they shouldn't - div.style.right = "60%"; - pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; - - // Support: IE 9 - 11 only - // Detect misreporting of content dimensions for box-sizing:border-box elements - boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; - - // Support: IE 9 only - // Detect overflow:scroll screwiness (gh-3699) - // Support: Chrome <=64 - // Don't get tricked when zoom affects offsetWidth (gh-4029) - div.style.position = "absolute"; - scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; - - 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; - } - - function roundPixelMeasures( measure ) { - return Math.round( parseFloat( measure ) ); - } - - var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, - reliableTrDimensionsVal, 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"; - - jQuery.extend( support, { - boxSizingReliable: function() { - computeStyleTests(); - return boxSizingReliableVal; - }, - pixelBoxStyles: function() { - computeStyleTests(); - return pixelBoxStylesVal; - }, - pixelPosition: function() { - computeStyleTests(); - return pixelPositionVal; - }, - reliableMarginLeft: function() { - computeStyleTests(); - return reliableMarginLeftVal; - }, - scrollboxSize: function() { - computeStyleTests(); - return scrollboxSizeVal; - }, - - // Support: IE 9 - 11+, Edge 15 - 18+ - // IE/Edge misreport `getComputedStyle` of table rows with width/height - // set in CSS while `offset*` properties report correct values. - // Behavior in IE 9 is more subtle than in newer versions & it passes - // some versions of this test; make sure not to make it pass there! - reliableTrDimensions: function() { - var table, tr, trChild, trStyle; - if ( reliableTrDimensionsVal == null ) { - table = document.createElement( "table" ); - tr = document.createElement( "tr" ); - trChild = document.createElement( "div" ); - - table.style.cssText = "position:absolute;left:-11111px"; - tr.style.height = "1px"; - trChild.style.height = "9px"; - - documentElement - .appendChild( table ) - .appendChild( tr ) - .appendChild( trChild ); - - trStyle = window.getComputedStyle( tr ); - reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; - - documentElement.removeChild( table ); - } - return reliableTrDimensionsVal; - } - } ); -} )(); - - -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 === "" && !isAttached( 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.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.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 cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style, - vendorProps = {}; - -// Return a vendor-prefixed property or undefined -function vendorPropName( 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 potentially-mapped jQuery.cssProps or vendor prefixed property -function finalPropName( name ) { - var final = jQuery.cssProps[ name ] || vendorProps[ name ]; - - if ( final ) { - return final; - } - if ( name in emptyStyle ) { - return name; - } - return vendorProps[ name ] = vendorPropName( name ) || name; -} - - -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" - }; - -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 boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { - var i = dimension === "width" ? 1 : 0, - extra = 0, - delta = 0; - - // Adjustment may not be necessary - if ( box === ( isBorderBox ? "border" : "content" ) ) { - return 0; - } - - for ( ; i < 4; i += 2 ) { - - // Both box models exclude margin - if ( box === "margin" ) { - delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); - } - - // If we get here with a content-box, we're seeking "padding" or "border" or "margin" - if ( !isBorderBox ) { - - // Add padding - delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // For "border" or "margin", add border - if ( box !== "padding" ) { - delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - - // But still keep track of it otherwise - } else { - extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - - // If we get here with a border-box (content + padding + border), we're seeking "content" or - // "padding" or "margin" - } else { - - // For "content", subtract padding - if ( box === "content" ) { - delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // For "content" or "padding", subtract border - if ( box !== "margin" ) { - delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - // Account for positive content-box scroll gutter when requested by providing computedVal - if ( !isBorderBox && computedVal >= 0 ) { - - // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border - // Assuming integer scroll gutter, subtract the rest and round down - delta += Math.max( 0, Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - computedVal - - delta - - extra - - 0.5 - - // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter - // Use an explicit zero to avoid NaN (gh-3964) - ) ) || 0; - } - - return delta; -} - -function getWidthOrHeight( elem, dimension, extra ) { - - // Start with computed style - var styles = getStyles( elem ), - - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). - // Fake content-box until we know it's needed to know the true value. - boxSizingNeeded = !support.boxSizingReliable() || extra, - isBorderBox = boxSizingNeeded && - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - valueIsBorderBox = isBorderBox, - - val = curCSS( elem, dimension, styles ), - offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); - - // Support: Firefox <=54 - // Return a confounding non-pixel value or feign ignorance, as appropriate. - if ( rnumnonpx.test( val ) ) { - if ( !extra ) { - return val; - } - val = "auto"; - } - - - // Support: IE 9 - 11 only - // Use offsetWidth/offsetHeight for when box sizing is unreliable. - // In those cases, the computed value can be trusted to be border-box. - if ( ( !support.boxSizingReliable() && isBorderBox || - - // Support: IE 10 - 11+, Edge 15 - 18+ - // IE/Edge misreport `getComputedStyle` of table rows with width/height - // set in CSS while `offset*` properties report correct values. - // Interestingly, in some cases IE 9 doesn't suffer from this issue. - !support.reliableTrDimensions() && nodeName( elem, "tr" ) || - - // Fall back to offsetWidth/offsetHeight when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - val === "auto" || - - // Support: Android <=4.1 - 4.3 only - // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) - !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && - - // Make sure the element is visible & connected - elem.getClientRects().length ) { - - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // Where available, offsetWidth/offsetHeight approximate border box dimensions. - // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the - // retrieved value as a content box dimension. - valueIsBorderBox = offsetProp in elem; - if ( valueIsBorderBox ) { - val = elem[ offsetProp ]; - } - } - - // Normalize "" and auto - val = parseFloat( val ) || 0; - - // Adjust for the element's box model - return ( val + - boxModelAdjustment( - elem, - dimension, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles, - - // Provide the current computed size to request scroll gutter calculation (gh-3589) - val - ) - ) + "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, - "gridArea": true, - "gridColumn": true, - "gridColumnEnd": true, - "gridColumnStart": true, - "gridRow": true, - "gridRowEnd": true, - "gridRowStart": 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: {}, - - // 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 = 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) - // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append - // "px" to a few hardcoded values. - if ( type === "number" && !isCustomProp ) { - 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 = 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, dimension ) { - jQuery.cssHooks[ dimension ] = { - 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, dimension, extra ); - } ) : - getWidthOrHeight( elem, dimension, extra ); - } - }, - - set: function( elem, value, extra ) { - var matches, - styles = getStyles( elem ), - - // Only read styles.position if the test has a chance to fail - // to avoid forcing a reflow. - scrollboxSizeBuggy = !support.scrollboxSize() && - styles.position === "absolute", - - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) - boxSizingNeeded = scrollboxSizeBuggy || extra, - isBorderBox = boxSizingNeeded && - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - subtract = extra ? - boxModelAdjustment( - elem, - dimension, - extra, - isBorderBox, - styles - ) : - 0; - - // Account for unreliable border-box dimensions by comparing offset* to computed and - // faking a content-box to get border and padding (gh-3699) - if ( isBorderBox && scrollboxSizeBuggy ) { - subtract -= Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - parseFloat( styles[ dimension ] ) - - boxModelAdjustment( elem, dimension, "border", false, styles ) - - 0.5 - ); - } - - // Convert to pixels if value adjustment is needed - if ( subtract && ( matches = rcssNum.exec( value ) ) && - ( matches[ 3 ] || "px" ) !== "px" ) { - - elem.style[ dimension ] = value; - value = jQuery.css( elem, dimension ); - } - - 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 ( prefix !== "margin" ) { - 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 && ( - jQuery.cssHooks[ tween.prop ] || - tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { - 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 = Date.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 - 15 - // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY and Edge just mirrors - // the overflowX value there. - 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 = 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 ( isFunction( result.stop ) ) { - jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = - result.stop.bind( result ); - } - return result; - } - } - - jQuery.map( props, createTween, animation ); - - if ( 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 ( 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 || - isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !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 ( 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 ) { - 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 = Date.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://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace - function stripAndCollapse( value ) { - var tokens = value.match( rnothtmlwhite ) || []; - return tokens.join( " " ); - } - - -function getClass( elem ) { - return elem.getAttribute && elem.getAttribute( "class" ) || ""; -} - -function classesToArray( value ) { - if ( Array.isArray( value ) ) { - return value; - } - if ( typeof value === "string" ) { - return value.match( rnothtmlwhite ) || []; - } - return []; -} - -jQuery.fn.extend( { - addClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - classes = classesToArray( value ); - - if ( classes.length ) { - 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 ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( !arguments.length ) { - return this.attr( "class", "" ); - } - - classes = classesToArray( value ); - - if ( classes.length ) { - 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, - isValidValue = type === "string" || Array.isArray( value ); - - if ( typeof stateVal === "boolean" && isValidValue ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - - if ( 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 ( isValidValue ) { - - // Toggle individual class names - i = 0; - self = jQuery( this ); - classNames = classesToArray( value ); - - 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, valueIsFunction, - 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; - } - - valueIsFunction = isFunction( value ); - - return this.each( function( i ) { - var val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( valueIsFunction ) { - 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 - - -support.focusin = "onfocusin" in window; - - -var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - stopPropagationCallback = function( e ) { - e.stopPropagation(); - }; - -jQuery.extend( jQuery.event, { - - trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - - cur = lastElement = 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 && !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() ) { - lastElement = cur; - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( - dataPriv.get( cur, "events" ) || Object.create( null ) - )[ 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 && isFunction( elem[ type ] ) && !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; - - if ( event.isPropagationStopped() ) { - lastElement.addEventListener( type, stopPropagationCallback ); - } - - elem[ type ](); - - if ( event.isPropagationStopped() ) { - lastElement.removeEventListener( type, stopPropagationCallback ); - } - - 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 ); - } - } -} ); - - -// 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() { - - // Handle: regular nodes (via `this.ownerDocument`), window - // (via `this.document`) & document (via `this`). - var doc = this.ownerDocument || this.document || 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.document || 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 = { guid: Date.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 && toType( 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 = isFunction( valueOrFunction ) ? - valueOrFunction() : - valueOrFunction; - - s[ s.length ] = encodeURIComponent( key ) + "=" + - encodeURIComponent( value == null ? "" : value ); - }; - - if ( a == null ) { - return ""; - } - - // 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 ( 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() + " " ] = - ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) - .concat( match[ 2 ] ); - } - } - match = responseHeaders[ key.toLowerCase() + " " ]; - } - return match == null ? null : match.join( ", " ); - }, - - // 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 - 15 - // 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 and should be processed, append data to url - if ( s.data && ( s.processData || typeof s.data === "string" ) ) { - 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.guid++ ) + - 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 ); - } - - // Use a noop converter for missing script - if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { - s.converters[ "text script" ] = function() {}; - } - - // 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 ( 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.ajaxPrefilter( function( s ) { - var i; - for ( i in s.headers ) { - if ( i.toLowerCase() === "content-type" ) { - s.contentType = s.headers[ i ] || ""; - } - } -} ); - - -jQuery._evalUrl = function( url, options, doc ) { - 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, - - // Only evaluate the response if it is successful (gh-4126) - // dataFilter is not invoked for failure responses, so using it instead - // of the default converter is kludgy but it works. - converters: { - "text script": function() {} - }, - dataFilter: function( response ) { - jQuery.globalEval( response, options, doc ); - } - } ); -}; - - -jQuery.fn.extend( { - wrapAll: function( html ) { - var wrap; - - if ( this[ 0 ] ) { - if ( 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 ( 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 htmlIsFunction = isFunction( html ); - - return this.each( function( i ) { - jQuery( this ).wrapAll( htmlIsFunction ? 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.ontimeout = - 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 = xhr.ontimeout = 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 or forced-by-attrs requests - if ( s.crossDomain || s.scriptAttrs ) { - var script, callback; - return { - send: function( _, complete ) { - script = jQuery( " - - - - - - - - - - - - - - -
-
-
- - -
- - -

Index

- -
- D - | E - | F - | G - | H - | I - | J - | L - | M - | N - | P - | Q - | R - | S - | U - | W - -
-

D

- - -
- -

E

- - -
- -

F

- - - -
- -

G

- - - -
- -

H

- - -
- -

I

- - - -
- -

J

- - -
- -

L

- - - -
- -

M

- - -
- -

N

- - -
- -

P

- - - -
- -

Q

- - - -
- -

R

- - -
- -

S

- - - -
    -
  • - stixdcpy.net - -
  • -
  • - stixdcpy.quicklook - -
  • -
  • - stixdcpy.sci_l1_corrections - -
  • -
  • - stixdcpy.time - -
  • -
- -

U

- - - -
- -

W

- - -
- - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/index.html b/docs/build/html/index.html deleted file mode 100755 index 1c06a3e..0000000 --- a/docs/build/html/index.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - Welcome to stixdcpy’s documentation! — stixdcpy 1.0 documentation - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Welcome to stixdcpy’s documentation!¶

-
-

Contents:

- -
-
-
-

Indices and tables¶

- -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/modules.html b/docs/build/html/modules.html deleted file mode 100755 index c83477d..0000000 --- a/docs/build/html/modules.html +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - - - - stixdcpy — stixdcpy 1.0 documentation - - - - - - - - - - - - - - - - - - - -
- - -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/objects.inv b/docs/build/html/objects.inv deleted file mode 100755 index f85bbcbc0b360ce76829fffc967723ccda6e5846..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 770 zcmV+d1O5CXAX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGk&bZK~G zV{my2BOq2~a&u{KZaN?eBOp|0Wgv28ZDDC{WMy(7Z)PBLXlZjGW@&6?AZc?TV{dJ6 za%FRKWn>_Ab7^j8AbMyn$M1OxGjNTE^w=u{LzzI+7KWonk=C}x zvgGO`jc>dLug8-h`74f_Qp@J1Nc;b-w7b$e+OQ)fWfhgxbs?$c5WSCdI~ixD;BTAh z^}A@j>K8zON-J*7TwVOJ9&LYo_XNVR*3o7Jcug56N){+#&bQwMm`u`eND2lK%-LRH z!=ykI8@!bFKNwQ%B~}zc7v%-4k{y8~qbwlUGohFA8d5!l91j6aVG)#xL@v=Qc(kA= z$0?ImLk>_fkp@=qP#S+8aVFI9i~2YLL$Wz17-5=AVf1oTXeqx;DgpAT6ea^x!eo4N zJ2CvVZOkR6)3@Ul8XqRVG6F)MMW={Axs>gcTO?-USw^a`0=g(hd&_gA2?Id@?JLyY zE5ztBE|J18VO>cC71S8!3o@j%$9i`dRm~MYrC?@i@4Vl8(3a24?EtVS%|lKXOqblC zfPQ(n{dRwPZzmpRplWLZiZTPm=K5|aoTZs-;8q=AA*pM)SkSh?xgN8S*LOunm!WI5tS2OomYpo%nGDBv2bka$wNI@_`;pmp=HOG74(Rvegv$b7x{FC(>=w$lk@DU%z$aENub8)PIuRtX%nAa8_39ZlR%lZHljP+mxIhI&P;L z - - - - - - Python Module Index — stixdcpy 1.0 documentation - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- - -

Python Module Index

- -
- s -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
- s
- stixdcpy -
    - stixdcpy.energylut -
    - stixdcpy.housekeeping -
    - stixdcpy.io -
    - stixdcpy.net -
    - stixdcpy.quicklook -
    - stixdcpy.sci_l1_corrections -
    - stixdcpy.time -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/search.html b/docs/build/html/search.html deleted file mode 100755 index 164311d..0000000 --- a/docs/build/html/search.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - Search — stixdcpy 1.0 documentation - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -

Search

- -
- -

- Please activate JavaScript to enable the search - functionality. -

-
- - -

- Searching for multiple words only shows matches that contain - all words. -

- - -
- - - -
- - - -
- -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/searchindex.js b/docs/build/html/searchindex.js deleted file mode 100755 index 58cc91d..0000000 --- a/docs/build/html/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({docnames:["index","modules","stixdcpy"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":4,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,sphinx:56},filenames:["index.rst","modules.rst","stixdcpy.rst"],objects:{"":{stixdcpy:[2,0,0,"-"]},"stixdcpy.energylut":{EnergyLUT:[2,1,1,""]},"stixdcpy.energylut.EnergyLUT":{from_file:[2,2,1,""],get_calibration_data:[2,2,1,""],get_data:[2,2,1,""],get_onboard_elut:[2,2,1,""],get_pixel_true_ebins:[2,2,1,""],get_true_energy_bin_edges:[2,2,1,""],info:[2,2,1,""],request:[2,2,1,""]},"stixdcpy.housekeeping":{Housekeeping:[2,1,1,""]},"stixdcpy.housekeeping.Housekeeping":{fetch:[2,2,1,""],from_fits:[2,2,1,""],get_data:[2,2,1,""],peek:[2,2,1,""]},"stixdcpy.io":{IO:[2,1,1,""]},"stixdcpy.io.IO":{load:[2,2,1,""],save:[2,2,1,""]},"stixdcpy.net":{FitsProduct:[2,1,1,""],FitsProductQueryResult:[2,1,1,""],JSONRequest:[2,1,1,""]},"stixdcpy.net.FitsProduct":{fetch:[2,2,1,""],fetch_bulk_science_by_request_id:[2,2,1,""],fetch_continuous_data:[2,2,1,""],get_fits:[2,2,1,""],query:[2,2,1,""],wget:[2,2,1,""]},"stixdcpy.net.FitsProductQueryResult":{fetch:[2,2,1,""],get_fits_ids:[2,2,1,""]},"stixdcpy.net.JSONRequest":{fetch_empheris:[2,2,1,""],fetch_light_curves:[2,2,1,""],fetch_onboard_and_true_eluts:[2,2,1,""],fetch_science_data:[2,2,1,""],post:[2,2,1,""]},"stixdcpy.quicklook":{LightCurves:[2,1,1,""],QuickLook:[2,1,1,""]},"stixdcpy.quicklook.LightCurves":{fetch:[2,2,1,""],get_data:[2,2,1,""],peek:[2,2,1,""]},"stixdcpy.sci_l1_corrections":{live_time_correction:[2,3,1,""]},"stixdcpy.time":{datetime2unix:[2,3,1,""],format_datetime:[2,3,1,""],get_now:[2,3,1,""],now:[2,3,1,""],unix2datetime:[2,3,1,""],unix2utc:[2,3,1,""],utc2datetime:[2,3,1,""],utc2unix:[2,3,1,""]},stixdcpy:{energylut:[2,0,0,"-"],housekeeping:[2,0,0,"-"],io:[2,0,0,"-"],net:[2,0,0,"-"],quicklook:[2,0,0,"-"],sci_l1_corrections:[2,0,0,"-"],time:[2,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:function"},terms:{"1":2,"2021":2,"class":2,"default":2,"do":2,"int":2,"return":2,"static":2,"super":[],"true":2,"var":2,A:2,If:2,It:2,The:2,__init__:[],_id:2,abov:2,alreadi:[],ancillarydata:1,api:2,asp:2,aspect:2,astropi:2,author:2,ax:2,bar:2,base:2,begin_utc:2,bkg:2,bool:2,bsd:[],cal:2,calibr:2,can:2,center:2,ch:2,classmethod:2,condit:2,content:1,correct:2,curv:2,data:2,data_typ:2,date:2,datetim:2,datetime2unix:2,dd:2,def:[],desc:2,descript:2,displai:2,doe:[],download:2,download_if_not_exist:[],dt:2,dtype:2,end_unix:[],end_utc:2,energi:2,energylut:1,entry_id:[],ephemeri:[],exist:[],f:[],fail:2,fals:2,fetch:2,fetch_bulk_science_by_request_id:2,fetch_continuous_data:2,fetch_empheri:2,fetch_light_curv:2,fetch_onboard_and_true_elut:2,fetch_science_data:2,ffl:2,fhnw:2,file:2,filenam:2,fit:2,fits_id:2,fits_typ:2,fitsproduct:2,fitsproductqueryresult:2,fitsrequest:[],flag:2,form:2,format:2,format_datetim:2,found:2,from:2,from_fil:2,from_fit:2,get:[],get_calibration_data:2,get_data:2,get_fit:2,get_fits_id:2,get_now:2,get_onboard_elut:2,get_pixel_true_ebin:2,get_true_energy_bin_edg:2,hkmax:2,hkmin:2,host:[],housekeep:1,hualin:2,id:[],index:0,info:2,input:[],io:1,json:2,jsonrequest:2,l0:2,l1:2,l1data:2,l2:2,l3:2,lc:2,legend_loc:2,light:2,lightcurv:2,link:2,list:[],live_time_correct:2,load:2,look:2,ltc:2,mm:2,mmthh:2,modul:[0,1],net:1,none:2,now:2,object:2,obs_begin:[],obs_end:[],option:2,packag:[0,1],packet:2,page:0,param:2,paramet:2,peek:2,pixel:2,plot:2,post:2,preprocess:[],product:2,product_typ:2,progress:2,progress_bar:2,provid:2,pub023:2,qlspec:2,queri:2,query_result:2,quick:2,quicklook:1,rais:[],receiv:2,request:2,request_id:2,resp:2,result:2,retriev:2,right:2,same:2,satistifi:2,save:2,sci_l1_correct:1,sciencedata:1,scil1:[],script:2,search:0,self:[],sep:2,server:2,shown:2,some:2,spec:2,ss:2,st:[],start:2,start_unix:[],start_utc:2,step:2,stix:2,stop:2,stop_utc:2,str:2,submodul:1,success:2,temporari:2,thi:2,time:1,timestamp:2,tool:2,ts:2,type:2,typeerror:[],unix2datetim:2,unix2utc:2,unix:2,unix_timestamp:2,upper:2,url:2,utc2datetim:2,utc2unix:2,utc:2,valu:2,view:[],wa:[],wget:2,which:2,xiao:2,yyyddmmhhmmss:2,yyyi:2},titles:["Welcome to stixdcpy\u2019s documentation!","stixdcpy","stixdcpy package"],titleterms:{ancillarydata:2,content:[0,2],document:0,energylut:2,housekeep:2,indic:0,io:2,modul:2,net:2,packag:2,quicklook:2,s:0,sci_l1_correct:2,sciencedata:2,stixdcpi:[0,1,2],submodul:2,tabl:0,time:2,welcom:0}}) \ No newline at end of file diff --git a/docs/build/html/stixdcpy.html b/docs/build/html/stixdcpy.html deleted file mode 100755 index f26dd4c..0000000 --- a/docs/build/html/stixdcpy.html +++ /dev/null @@ -1,441 +0,0 @@ - - - - - - - - - stixdcpy package — stixdcpy 1.0 documentation - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

stixdcpy package¶

-
-

Submodules¶

-
-
-

stixdcpy.ancillarydata module¶

-
-
-

stixdcpy.energylut module¶

-

This script provides APIs to retrieve energy calibration data from STIX data center ,and some tools to display the data -Author: Hualin Xiao (hualin.xiao@fhnw.ch) -Date: Sep. 1, 2021

-
-
-class stixdcpy.energylut.EnergyLUT¶
-

Bases: stixdcpy.io.IO

-
-
-classmethod from_file(filename)¶
-
- -
-
-get_calibration_data()¶
-
- -
-
-get_data()¶
-
- -
-
-get_onboard_elut()¶
-
- -
-
-get_pixel_true_ebins(pixel)¶
-
- -
-
-get_true_energy_bin_edges()¶
-
- -
-
-info()¶
-
- -
-
-classmethod request(utc)¶
-
- -
- -
-
-

stixdcpy.housekeeping module¶

-

This module provides APIs to retrieve Housekeeping data from STIX data center ,and some tools to display the data -Author: Hualin Xiao (hualin.xiao@fhnw.ch) -Date: Sep. 1, 2021

-
-
-class stixdcpy.housekeeping.Housekeeping(filename)¶
-

Bases: stixdcpy.io.IO

-
-
-classmethod fetch(start_utc: str, end_utc: str)¶
-
- -
-
-classmethod from_fits(filename)¶
-
- -
-
-get_data()¶
-
- -
-
-peek(ax=None, legend_loc='upper right')¶
-
- -
- -
-
-

stixdcpy.io module¶

-
-
-class stixdcpy.io.IO¶
-

Bases: object

-

Base object

-
-
-load(filename)¶
-
- -
-
-save(data, filename)¶
-
- -
- -
-
-

stixdcpy.net module¶

-

This module provides APIs to retrieve data from STIX data center -Author: Hualin Xiao (hualin.xiao@fhnw.ch) -Date: Sep. 1, 2021

-
-
-class stixdcpy.net.FitsProduct¶
-

Bases: object

-

Request FITS format data from STIX data center

-
-
-static fetch(query_results)¶
-
- -
-
-static fetch_bulk_science_by_request_id(request_id)¶
-
- -
-
-static fetch_continuous_data(start_utc, end_utc, data_type)¶
-
- -
-
-static get_fits(fits_id, progress_bar=True)¶
-

Query data from pub023 and download FITS file from the server. -A fits file will be received for the packets which satistify the query condition. -If no data is found on pub023, a json object will be received

-
-
Parameters
-
    -
  • start_utc (str) – start UTC in formats yyyy-dd-mmTHH:MM:SS, yyyddmmHHMMSS, or datetime

  • -
  • stop_utc ([type]) – stop UTC formats the same as above

  • -
  • fits_type (str, optional) – data product type It can be ‘l0’, ‘l1’, ‘l2’, ‘l3’, ‘spec’, ‘qlspec’, ‘asp’, ‘aspect’, ‘lc’, ‘bkg’,

  • -
-
-
-

‘var’, ‘ffl’, ‘cal’, ‘hkmin’ or ‘hkmax’. Defaults to ‘lc’.

-
-
Returns
-

astropy fits object if the request is successful; None if it is failed or no result returns

-
-
-
- -
-
-static query(start_utc, stop_utc, product_type='lc')¶
-
- -
-
-static wget(url: str, desc: str, progress_bar=True)¶
-
-
Download a file from the link and save the file to a temporary file.

Downloading progress will be shown in a progress bar

-
-
-
-
Parameters
-
    -
  • url (str) – URL

  • -
  • desc (str) – description to be shown on the progress bar

  • -
-
-
Returns
-

temporary filename

-
-
-
- -
- -
-
-class stixdcpy.net.FitsProductQueryResult(resp)¶
-

Bases: object

-
-
-fetch()¶
-
- -
-
-get_fits_ids()¶
-
- -
- -
-
-class stixdcpy.net.JSONRequest¶
-

Bases: object

-

Request json format data from STIX data center

-
-
-static fetch_empheris(start_utc: str, end_utc: str, steps=1)¶
-
- -
-
-static fetch_light_curves(begin_utc: str, end_utc: str, ltc: bool)¶
-
- -
-
-fetch_onboard_and_true_eluts()¶
-
- -
-
-static fetch_science_data(_id: int)¶
-
- -
-
-static post(url, form)¶
-
- -
- -
-
-

stixdcpy.quicklook module¶

-

This module provides APIs to retrieve Quick-look data from STIX data center ,and some tools to display the data -Author: Hualin Xiao (hualin.xiao@fhnw.ch) -Date: Sep. 1, 2021

-
-
-class stixdcpy.quicklook.LightCurves(data)¶
-

Bases: stixdcpy.quicklook.QuickLook

-
-
-classmethod fetch(start_utc: str, end_utc: str, ltc=False)¶
-
- -
-
-get_data()¶
-
- -
-
-peek(ax=None, legend_loc='upper right')¶
-

Plot light curves -:param ltc: light time correction flag. The default value is False. Do light time correction if ltc=True

-
- -
- -
-
-class stixdcpy.quicklook.QuickLook¶
-

Bases: stixdcpy.io.IO

-
- -
-
-

stixdcpy.sci_l1_corrections module¶

-

This module provides APIs to retrieve data from STIX data center -Author: Hualin Xiao (hualin.xiao@fhnw.ch) -Date: Sep. 1, 2021

-
-
-stixdcpy.sci_l1_corrections.live_time_correction(l1data)¶
-
- -
-
-

stixdcpy.sciencedata module¶

-
-
-

stixdcpy.time module¶

-
-
-stixdcpy.time.datetime2unix(timestamp)¶
-
- -
-
-stixdcpy.time.format_datetime(dt)¶
-
- -
-
-stixdcpy.time.get_now(dtype='unix')¶
-
- -
-
-stixdcpy.time.now()¶
-
- -
-
-stixdcpy.time.unix2datetime(unix_timestamp)¶
-
- -
-
-stixdcpy.time.unix2utc(ts)¶
-
- -
-
-stixdcpy.time.utc2datetime(utc)¶
-
- -
-
-stixdcpy.time.utc2unix(utc)¶
-
- -
-
-

Module contents¶

-
-
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100755 index 6247f7e..0000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/docs/source/conf.py b/docs/source/conf.py deleted file mode 100755 index ad620b2..0000000 --- a/docs/source/conf.py +++ /dev/null @@ -1,56 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -import os -import sys -sys.path.insert(0, os.path.abspath('../../stixdcpy')) -#sys.path.insert(0, os.path.abspath('../stixdcpy')) - -# -- Project information ----------------------------------------------------- - -project = 'stixdcpy' -copyright = '2021, Hualin Xiao' -author = 'Hualin Xiao' - -# The full version, including alpha/beta/rc tags -release = '1.0' - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -#extensions = [ -#] -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'alabaster' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] diff --git a/docs/source/index.rst b/docs/source/index.rst deleted file mode 100755 index f1c3472..0000000 --- a/docs/source/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -.. stixdcpy documentation master file, created by - sphinx-quickstart on Tue Sep 7 13:51:38 2021. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to stixdcpy's documentation! -==================================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - modules - - - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/source/modules.rst b/docs/source/modules.rst deleted file mode 100755 index 9d3c49b..0000000 --- a/docs/source/modules.rst +++ /dev/null @@ -1,7 +0,0 @@ -stixdcpy -======== - -.. toctree:: - :maxdepth: 4 - - stixdcpy diff --git a/docs/source/stixdcpy.rst b/docs/source/stixdcpy.rst deleted file mode 100755 index f6d07bb..0000000 --- a/docs/source/stixdcpy.rst +++ /dev/null @@ -1,85 +0,0 @@ -stixdcpy package -================ - -Submodules ----------- - -stixdcpy.ancillarydata module ------------------------------ - -.. automodule:: stixdcpy.ancillarydata - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.energylut module -------------------------- - -.. automodule:: stixdcpy.energylut - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.housekeeping module ----------------------------- - -.. automodule:: stixdcpy.housekeeping - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.io module ------------------- - -.. automodule:: stixdcpy.io - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.net module -------------------- - -.. automodule:: stixdcpy.net - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.quicklook module -------------------------- - -.. automodule:: stixdcpy.quicklook - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.sci\_l1\_corrections module ------------------------------------- - -.. automodule:: stixdcpy.sci_l1_corrections - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.sciencedata module ---------------------------- - -.. automodule:: stixdcpy.sciencedata - :members: - :undoc-members: - :show-inheritance: - -stixdcpy.time module --------------------- - -.. automodule:: stixdcpy.time - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: stixdcpy - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/stixdcpy/ancillary.html b/docs/stixdcpy/ancillary.html new file mode 100644 index 0000000..5cb5085 --- /dev/null +++ b/docs/stixdcpy/ancillary.html @@ -0,0 +1,693 @@ + + + + + + +stixdcpy.ancillary API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.ancillary

+
+
+

This module provides APIs to retrieve Quick-look data from STIX data center +,and some tools to display the data +Author: Hualin Xiao (hualin.xiao@fhnw.ch) +Date: Sep. 1, 2021

+
+ +Expand source code + +
#!/usr/bin/python
+"""
+    This module provides APIs to retrieve Quick-look data from STIX data center  ,and some tools to display the data
+    Author: Hualin Xiao (hualin.xiao@fhnw.ch)
+    Date: Sep. 1, 2021
+
+"""
+import numpy as np
+import pandas as pd
+from matplotlib import patches
+from matplotlib import pyplot as plt
+
+from stixdcpy import io as sio
+from stixdcpy.logger import logger
+from stixdcpy.net import JSONRequest as jreq
+
+
+class Ephemeris(sio.IO):
+    def __init__(self, start_utc, end_utc, data):
+        self.start_utc = start_utc
+        self.end_utc = end_utc
+        self.data = data
+
+    @classmethod
+    def from_sdc(cls, start_utc: str, end_utc=None, steps=1):
+        """
+        Fetch ephemeris from STIX data center
+        Args:
+            start_utc: str
+            Start UTC
+            end_utc: str
+            End UTC
+            steps:
+            Number of data steps
+        Returns:
+            ephemeris: object
+
+        """
+        if end_utc is None:
+            end_utc = start_utc
+        orbit= jreq.request_ephemeris(start_utc, end_utc, steps)
+        att=jreq.request_attitude(start_utc, end_utc, steps)
+        data={'orbit':orbit,'attitude':att}
+        return cls(start_utc, end_utc, data)
+
+    @classmethod
+    def from_npy(cls, filename):
+        """
+        Load ephemeris data from a npz file
+        Args:
+            filename: str
+            npz filename
+        """
+        with np.load(filename, allow_picke=True) as data:
+            item = data.item()
+            _data = item['data']
+            start, end = item['start'], item['end']
+            cls(start, end, _data)
+
+    def save_npy(cls, filename):
+        """
+        Save ephemeris data as npy format
+        Args:
+            filename: str
+            npy filename
+        """
+        _data = {
+            'data': self.data,
+            'start': self.start_utc,
+            'end': self.end_utc
+        }
+        np.save(filename, _data)
+
+    def to_pandas(self):
+        """convert ephemeris data to pandas data frame
+
+        Returns:
+            df: pandas data frame
+
+
+        """
+        return pd.DataFrame(self.data)
+
+    def __getattr__(self, name):
+        if name == 'data':
+            return self.data
+
+    def get_data(self):
+        return self.data
+
+    def peek(self, ax=None):
+        if not self.data:
+            logger.error(f'Data not loaded. ')
+            return None
+        if not ax:
+            _, ax = plt.subplots()
+        data = self.data['orbit']
+        if not data or 'error' in data:
+            logger.error(f'Data not available. ')
+            return None
+        sun = patches.Circle((0.0, 0.0), 0.25, alpha=0.8, fc='yellow')
+        plt.text(0, 0, 'Sun')
+        ax.add_patch(sun)
+        earth = patches.Circle((-1, 0), 0.12, alpha=0.8, fc='green')
+        ax.add_patch(earth)
+        ax.text(-1, 0, 'Earth')
+        ax.plot(data['x'], data['y'])
+        ax.plot(data['x'][-1], data['y'][-1], 'x')
+        ax.text(data['x'][-1], data['y'][-1], 'SOLO')
+        ax.set_xlabel('X (au)')
+        ax.set_ylabel('Y (au)')
+        ax.set_xlim(-2, 2)
+        ax.set_ylim(-2, 2)
+        ax.set_aspect('equal')
+        ax.grid()
+        plt.title(f'SOLO Location at {self.start_utc}')
+        return ax
+class STIXPointing(Ephemeris):
+    def __init__(self, utc,  data):
+        self.utc= utc
+        self.data = data
+    @classmethod
+    def from_sdc(cls, utc):
+        """
+        Fetch ephemeris from STIX data center
+        Args:
+            start_utc: str
+            Start UTC
+            end_utc: str
+            End UTC
+            steps:
+            Number of data steps
+        Returns:
+            ephemeris: object
+
+        """
+        data= jreq.request_pointing(utc)
+        return cls(utc, data)
+    def peek(self, ax=None):
+        if not self.data:
+            logger.error(f'Data not loaded. ')
+            return None
+        if not ax:
+            _, ax = plt.subplots()
+        data = self.data
+        if not data or 'error' in data:
+            logger.error(f'Data not available. ')
+            return None
+        ax.plot(data['fov']['x'], data['fov']['y'],'--', label='STIX FOV',color='black')
+        ax.plot([data['sun_center'][0]], [data['sun_center'][1]], marker='+', label='Sun Center')
+        ax.plot(data['limb']['x'], data['limb']['y'],label='Solar limb',color='red')
+        center=[round(x,1) for x in data["sun_center"]]
+        ax.set_title(f'Solar center: {center}  arcsec \n {data["time"]} UT ')
+        nsew_coords=np.array(data['nsew'])
+        ax.plot(nsew_coords[0:2:,0], nsew_coords[0:2,1])
+        ax.plot(nsew_coords[2::,0], nsew_coords[2:,1])
+        ax.text(nsew_coords[0,0], nsew_coords[0,1],'N')
+        ax.text(nsew_coords[2,0], nsew_coords[2,1],'E')
+        ax.set_aspect('equal')
+        ax.legend(loc='upper right')
+        ax.set_xlim(-5400, 5400)
+        ax.grid(True)
+        ax.set_xlabel('STIX X (arcsec)')
+        ax.set_ylabel('STIX Y (arcsec)')
+        return ax
+        
+    
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class Ephemeris +(start_utc, end_utc, data) +
+
+

Base object

+
+ +Expand source code + +
class Ephemeris(sio.IO):
+    def __init__(self, start_utc, end_utc, data):
+        self.start_utc = start_utc
+        self.end_utc = end_utc
+        self.data = data
+
+    @classmethod
+    def from_sdc(cls, start_utc: str, end_utc=None, steps=1):
+        """
+        Fetch ephemeris from STIX data center
+        Args:
+            start_utc: str
+            Start UTC
+            end_utc: str
+            End UTC
+            steps:
+            Number of data steps
+        Returns:
+            ephemeris: object
+
+        """
+        if end_utc is None:
+            end_utc = start_utc
+        orbit= jreq.request_ephemeris(start_utc, end_utc, steps)
+        att=jreq.request_attitude(start_utc, end_utc, steps)
+        data={'orbit':orbit,'attitude':att}
+        return cls(start_utc, end_utc, data)
+
+    @classmethod
+    def from_npy(cls, filename):
+        """
+        Load ephemeris data from a npz file
+        Args:
+            filename: str
+            npz filename
+        """
+        with np.load(filename, allow_picke=True) as data:
+            item = data.item()
+            _data = item['data']
+            start, end = item['start'], item['end']
+            cls(start, end, _data)
+
+    def save_npy(cls, filename):
+        """
+        Save ephemeris data as npy format
+        Args:
+            filename: str
+            npy filename
+        """
+        _data = {
+            'data': self.data,
+            'start': self.start_utc,
+            'end': self.end_utc
+        }
+        np.save(filename, _data)
+
+    def to_pandas(self):
+        """convert ephemeris data to pandas data frame
+
+        Returns:
+            df: pandas data frame
+
+
+        """
+        return pd.DataFrame(self.data)
+
+    def __getattr__(self, name):
+        if name == 'data':
+            return self.data
+
+    def get_data(self):
+        return self.data
+
+    def peek(self, ax=None):
+        if not self.data:
+            logger.error(f'Data not loaded. ')
+            return None
+        if not ax:
+            _, ax = plt.subplots()
+        data = self.data['orbit']
+        if not data or 'error' in data:
+            logger.error(f'Data not available. ')
+            return None
+        sun = patches.Circle((0.0, 0.0), 0.25, alpha=0.8, fc='yellow')
+        plt.text(0, 0, 'Sun')
+        ax.add_patch(sun)
+        earth = patches.Circle((-1, 0), 0.12, alpha=0.8, fc='green')
+        ax.add_patch(earth)
+        ax.text(-1, 0, 'Earth')
+        ax.plot(data['x'], data['y'])
+        ax.plot(data['x'][-1], data['y'][-1], 'x')
+        ax.text(data['x'][-1], data['y'][-1], 'SOLO')
+        ax.set_xlabel('X (au)')
+        ax.set_ylabel('Y (au)')
+        ax.set_xlim(-2, 2)
+        ax.set_ylim(-2, 2)
+        ax.set_aspect('equal')
+        ax.grid()
+        plt.title(f'SOLO Location at {self.start_utc}')
+        return ax
+
+

Ancestors

+ +

Subclasses

+ +

Static methods

+
+
+def from_npy(filename) +
+
+

Load ephemeris data from a npz file

+

Args

+
+
filename
+
str
+
+

npz filename

+
+ +Expand source code + +
@classmethod
+def from_npy(cls, filename):
+    """
+    Load ephemeris data from a npz file
+    Args:
+        filename: str
+        npz filename
+    """
+    with np.load(filename, allow_picke=True) as data:
+        item = data.item()
+        _data = item['data']
+        start, end = item['start'], item['end']
+        cls(start, end, _data)
+
+
+
+def from_sdc(start_utc: str, end_utc=None, steps=1) +
+
+

Fetch ephemeris from STIX data center

+

Args

+
+
start_utc
+
str
+
Start UTC
+
end_utc
+
str
+
+

End UTC +steps: +Number of data steps

+

Returns

+
+
ephemeris
+
object
+
+
+ +Expand source code + +
@classmethod
+def from_sdc(cls, start_utc: str, end_utc=None, steps=1):
+    """
+    Fetch ephemeris from STIX data center
+    Args:
+        start_utc: str
+        Start UTC
+        end_utc: str
+        End UTC
+        steps:
+        Number of data steps
+    Returns:
+        ephemeris: object
+
+    """
+    if end_utc is None:
+        end_utc = start_utc
+    orbit= jreq.request_ephemeris(start_utc, end_utc, steps)
+    att=jreq.request_attitude(start_utc, end_utc, steps)
+    data={'orbit':orbit,'attitude':att}
+    return cls(start_utc, end_utc, data)
+
+
+
+

Methods

+
+
+def get_data(self) +
+
+
+
+ +Expand source code + +
def get_data(self):
+    return self.data
+
+
+
+def peek(self, ax=None) +
+
+
+
+ +Expand source code + +
def peek(self, ax=None):
+    if not self.data:
+        logger.error(f'Data not loaded. ')
+        return None
+    if not ax:
+        _, ax = plt.subplots()
+    data = self.data['orbit']
+    if not data or 'error' in data:
+        logger.error(f'Data not available. ')
+        return None
+    sun = patches.Circle((0.0, 0.0), 0.25, alpha=0.8, fc='yellow')
+    plt.text(0, 0, 'Sun')
+    ax.add_patch(sun)
+    earth = patches.Circle((-1, 0), 0.12, alpha=0.8, fc='green')
+    ax.add_patch(earth)
+    ax.text(-1, 0, 'Earth')
+    ax.plot(data['x'], data['y'])
+    ax.plot(data['x'][-1], data['y'][-1], 'x')
+    ax.text(data['x'][-1], data['y'][-1], 'SOLO')
+    ax.set_xlabel('X (au)')
+    ax.set_ylabel('Y (au)')
+    ax.set_xlim(-2, 2)
+    ax.set_ylim(-2, 2)
+    ax.set_aspect('equal')
+    ax.grid()
+    plt.title(f'SOLO Location at {self.start_utc}')
+    return ax
+
+
+
+def save_npy(cls, filename) +
+
+

Save ephemeris data as npy format

+

Args

+
+
filename
+
str
+
+

npy filename

+
+ +Expand source code + +
def save_npy(cls, filename):
+    """
+    Save ephemeris data as npy format
+    Args:
+        filename: str
+        npy filename
+    """
+    _data = {
+        'data': self.data,
+        'start': self.start_utc,
+        'end': self.end_utc
+    }
+    np.save(filename, _data)
+
+
+
+def to_pandas(self) +
+
+

convert ephemeris data to pandas data frame

+

Returns

+
+
df
+
pandas data frame
+
+
+ +Expand source code + +
def to_pandas(self):
+    """convert ephemeris data to pandas data frame
+
+    Returns:
+        df: pandas data frame
+
+
+    """
+    return pd.DataFrame(self.data)
+
+
+
+

Inherited members

+ +
+
+class STIXPointing +(utc, data) +
+
+

Base object

+
+ +Expand source code + +
class STIXPointing(Ephemeris):
+    def __init__(self, utc,  data):
+        self.utc= utc
+        self.data = data
+    @classmethod
+    def from_sdc(cls, utc):
+        """
+        Fetch ephemeris from STIX data center
+        Args:
+            start_utc: str
+            Start UTC
+            end_utc: str
+            End UTC
+            steps:
+            Number of data steps
+        Returns:
+            ephemeris: object
+
+        """
+        data= jreq.request_pointing(utc)
+        return cls(utc, data)
+    def peek(self, ax=None):
+        if not self.data:
+            logger.error(f'Data not loaded. ')
+            return None
+        if not ax:
+            _, ax = plt.subplots()
+        data = self.data
+        if not data or 'error' in data:
+            logger.error(f'Data not available. ')
+            return None
+        ax.plot(data['fov']['x'], data['fov']['y'],'--', label='STIX FOV',color='black')
+        ax.plot([data['sun_center'][0]], [data['sun_center'][1]], marker='+', label='Sun Center')
+        ax.plot(data['limb']['x'], data['limb']['y'],label='Solar limb',color='red')
+        center=[round(x,1) for x in data["sun_center"]]
+        ax.set_title(f'Solar center: {center}  arcsec \n {data["time"]} UT ')
+        nsew_coords=np.array(data['nsew'])
+        ax.plot(nsew_coords[0:2:,0], nsew_coords[0:2,1])
+        ax.plot(nsew_coords[2::,0], nsew_coords[2:,1])
+        ax.text(nsew_coords[0,0], nsew_coords[0,1],'N')
+        ax.text(nsew_coords[2,0], nsew_coords[2,1],'E')
+        ax.set_aspect('equal')
+        ax.legend(loc='upper right')
+        ax.set_xlim(-5400, 5400)
+        ax.grid(True)
+        ax.set_xlabel('STIX X (arcsec)')
+        ax.set_ylabel('STIX Y (arcsec)')
+        return ax
+
+

Ancestors

+ +

Methods

+
+
+def peek(self, ax=None) +
+
+
+
+ +Expand source code + +
def peek(self, ax=None):
+    if not self.data:
+        logger.error(f'Data not loaded. ')
+        return None
+    if not ax:
+        _, ax = plt.subplots()
+    data = self.data
+    if not data or 'error' in data:
+        logger.error(f'Data not available. ')
+        return None
+    ax.plot(data['fov']['x'], data['fov']['y'],'--', label='STIX FOV',color='black')
+    ax.plot([data['sun_center'][0]], [data['sun_center'][1]], marker='+', label='Sun Center')
+    ax.plot(data['limb']['x'], data['limb']['y'],label='Solar limb',color='red')
+    center=[round(x,1) for x in data["sun_center"]]
+    ax.set_title(f'Solar center: {center}  arcsec \n {data["time"]} UT ')
+    nsew_coords=np.array(data['nsew'])
+    ax.plot(nsew_coords[0:2:,0], nsew_coords[0:2,1])
+    ax.plot(nsew_coords[2::,0], nsew_coords[2:,1])
+    ax.text(nsew_coords[0,0], nsew_coords[0,1],'N')
+    ax.text(nsew_coords[2,0], nsew_coords[2,1],'E')
+    ax.set_aspect('equal')
+    ax.legend(loc='upper right')
+    ax.set_xlim(-5400, 5400)
+    ax.grid(True)
+    ax.set_xlabel('STIX X (arcsec)')
+    ax.set_ylabel('STIX Y (arcsec)')
+    return ax
+
+
+
+

Inherited members

+ +
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/cfl.html b/docs/stixdcpy/cfl.html new file mode 100644 index 0000000..33edcc3 --- /dev/null +++ b/docs/stixdcpy/cfl.html @@ -0,0 +1,53 @@ + + + + + + +stixdcpy.cfl API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.cfl

+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/correction.html b/docs/stixdcpy/correction.html new file mode 100644 index 0000000..04583cd --- /dev/null +++ b/docs/stixdcpy/correction.html @@ -0,0 +1,645 @@ + + + + + + +stixdcpy.correction API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.correction

+
+
+

This module provides algorithms to correct detector effects +Author: Hualin Xiao (hualin.xiao@fhnw.ch) +Date: Sep. 1, 2021

+
+ +Expand source code + +
#!/usr/bin/python
+"""
+    This module provides algorithms to correct detector effects
+    Author: Hualin Xiao (hualin.xiao@fhnw.ch)
+    Date: Sep. 1, 2021
+
+"""
+import numpy as np
+from matplotlib import pyplot as plt
+
+from stixdcpy import instrument as inst
+from stixdcpy import science
+from stixdcpy import time as sdt
+from stixdcpy.logger import logger
+
+DETECTOR_GROUPS = [[1, 2], [6, 7], [5, 11], [12, 13], [14, 15], [10, 16],
+                   [8, 9], [3, 4], [31, 32], [26, 27], [22, 28], [20, 21],
+                   [18, 19], [17, 23], [24, 25], [29, 30]]
+DET_SIBLINGS = {
+    0: 1,
+    1: 0,
+    5: 6,
+    6: 5,
+    4: 10,
+    10: 4,
+    11: 12,
+    12: 11,
+    13: 14,
+    14: 13,
+    9: 15,
+    15: 9,
+    7: 8,
+    8: 7,
+    2: 3,
+    3: 2,
+    30: 31,
+    31: 30,
+    25: 26,
+    26: 25,
+    21: 27,
+    27: 21,
+    19: 20,
+    20: 19,
+    17: 18,
+    18: 17,
+    16: 22,
+    22: 16,
+    23: 24,
+    24: 23,
+    28: 29,
+    29: 28
+}
+
+# detector sibling index
+
+
+class BackgroundSubtraction(object):
+    def __init__(self, l1sig: science.ScienceL1, l1bkg: science.ScienceL1):
+        """
+                   do background subtraction
+                Arguments
+                l1sig: a L1product instance containing the signal
+                l1bkg: a L1Product instance containing the background
+
+                """
+        self.l1sig = l1sig
+        self.l1bkg = l1bkg
+
+        dmask = self.l1bkg.energy_bin_mask - self.l1sig.energy_bin_mask
+        if np.any(dmask < 0):
+            logger.error(
+                'Background subtraction failed due to the background energy range does not cover the signal energy range  '
+            )
+            return
+
+        #mean_pixel_rate_clip = self.l1bkg.mean_pixel_rate_spectra * self.l1sig.inverse_energy_bin_mask
+
+        self.pixel_bkg_counts = np.array([
+            int_time * self.l1bkg.mean_pixel_rate_spectra
+            for int_time in self.l1sig.timedel
+        ])
+        # set counts beyond the signal energy range to 0
+        self.subtracted_counts = (self.l1sig.counts - self.pixel_bkg_counts
+                                  ) * self.l1sig.inverse_energy_bin_mask
+
+        # Dead time correction needs to be included in the future
+        self.subtracted_counts_err = np.sqrt(
+            self.l1sig.counts + np.array([int_time * self.l1bkg.mean_pixel_rate_spectra_err ** 2 for int_time in self.l1sig.timedel])) * \
+            self.l1sig.inverse_energy_bin_mask
+        self.bkg_subtracted_spectrogram = np.sum(self.subtracted_counts,
+                                                 axis=(1, 2))
+
+    def peek(self):
+        fig, axs = plt.subplots(2, 2)
+        self.l1sig.peek(axs[0, 0])
+        self.l1bkg.peek(axs[0, 1])
+        X, Y = np.meshgrid(self.l1sig.time,
+                           np.arange(self.l1sig.min_ebin, self.l1sig.max_ebin))
+        im = axs[1, 0].pcolormesh(
+            X, Y,
+            np.transpose(
+                self.bkg_subtracted_spectrogram[:, self.l1sig.min_ebin:self.
+                                                l1sig.max_ebin]))
+        axs[1, 0].set_yticks(self.l1sig.energies['channel']
+                             [self.l1sig.min_ebin:self.l1sig.max_ebin:2])
+        axs[1, 0].set_yticklabels(
+            self.l1sig.energy_bin_names[self.l1sig.min_ebin:self.l1sig.
+                                        max_ebin:2])
+        fig = plt.gcf()
+        cbar = fig.colorbar(im, ax=axs[1, 0])
+        cbar.set_label('Counts')
+        axs[1, 0].set_title('Bkg sub. counts')
+        axs[1, 0].set_ylabel('Energy range(keV')
+        axs[1, 0].set_xlabel(f"Seconds since {self.l1sig.T0}s ")
+        axs[1, 1].plot(np.sum(self.l1sig.spectrogram, axis=0),
+                       drawstyle='steps-mid',
+                       label='Before subtraction')
+        axs[1, 1].plot(np.sum(self.bkg_subtracted_spectrogram, axis=0),
+                       drawstyle="steps-mid",
+                       label='After subtraction')
+        axs[1, 1].plot(np.sum(self.pixel_bkg_counts, axis=(0, 1, 2)),
+                       drawstyle="steps-mid",
+                       label='background')
+        axs[1, 1].legend()
+
+    def get_background_subtracted_spectrum(self, start_utc=None, end_utc=None):
+        """
+        Get signal background subtracted spectrum
+
+        """
+        start_unix = sdt.utc2unix(start_utc)
+        end_unix = sdt.utc2unix(end_utc)
+        start_time = start_unix - self.l1sig.T0_unix
+        end_time = end_unix - self.l1sig.T0_unix
+        start_i_tbin = np.argmax(
+            self.l1sig.time - 0.5 * self.l1sig.timedel >= start_time) if (
+                0 <= start_time <= self.l1sig.duration) else 0
+
+        end_i_tbin = np.argmin(
+            self.l1sig.time + 0.5 * self.l1sig.timedel <= end_time) if (
+                start_time <= end_time <= self.l1sig.duration) else len(
+                    self.l1sig.time)
+        time_span = self.l1sig.time[end_i_tbin] - self.l1sig.time[
+            start_i_tbin] + 0.5 * self.l1sig.timedel[
+                start_i_tbin] + 0.5 * self.l1sig.timedel[end_i_tbin]
+
+        bkg_sub_spectra = np.sum(
+            self.subtracted_counts[start_i_tbin:end_i_tbin, :, :, :],
+            axis=(0, 1, 2)) / time_span,
+        bkg_sub_spectra_err = np.sqrt(
+            np.sum(self.subtracted_counts_err[start_i_tbin:end_i_tbin, :, :, :]
+                   ** 2,
+                   axis=(0, 1, 2))) / time_span
+        return bkg_sub_spectra, bkg_sub_spectra_err
+
+
+class LiveTimeCorrection(object):
+    pass
+    """
+    #counts is np.array   time_bins, detector, pixel, energy bins
+    trigger_rates=l1data['triggers'][1:,:]/l1data['timedel'][:-1,None]
+    # delta time is off by 1 time bin due a bug in the
+    out=np.copy(trigger_rates)
+    tau=11e-6
+    live_time=1 - tau*trig
+    photo_in=trig/(live_time)
+        """
+
+    @classmethod
+    def L1_live_time_correction(cls, triggers, counts_arr, time_bins):
+        """ Live time correction
+        Args
+            triggers: ndarray
+                triggers in the spectrogram
+            counts_arr:ndarray
+                counts in the spectrogram
+            time_bins: ndarray
+                time_bins in the spectrogram
+        Returns
+        live_time_ratio: ndarray
+            live time ratio of detectors
+        count_rate:
+            corrected count rate
+        photons_in:
+            rate of photons illuminating the detector group
+
+        """
+
+        fpga_tau=10.1e-6
+        asic_tau=2.63e-6
+        trig_tau = fpga_tau+asic_tau
+
+        time_bins = time_bins[:, None]
+        photons_in = triggers/(time_bins-trig_tau*triggers)
+        #photon rate calculated using triggers 
+
+        correction_factors= np.zeros((time_bins.size, 32))
+        time_bins = time_bins[:, :, None, None]
+
+        time_bins = time_bins[:, :, None, None]
+        count_rates = counts_arr/time_bins
+        # print(counts_arr.shape)
+        for det in range(32):
+            trig_idx=inst.detector_id_to_trigger_index[det]
+            nin=photons_in[:,trig_idx]
+            cor_factor=0.94
+            live_ratio[:,det]=np.exp(- cor_factor*nin*asic_tau*1e-6)/(1+ nin*trig_tau)
+
+        return correction_factors, corrected_rates , count_rates,photons_in
+
+
+
+class TransmissionCorrection(object):
+    pass
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class BackgroundSubtraction +(l1sig: ScienceL1, l1bkg: ScienceL1) +
+
+

do background subtraction +Arguments +l1sig: a L1product instance containing the signal +l1bkg: a L1Product instance containing the background

+
+ +Expand source code + +
class BackgroundSubtraction(object):
+    def __init__(self, l1sig: science.ScienceL1, l1bkg: science.ScienceL1):
+        """
+                   do background subtraction
+                Arguments
+                l1sig: a L1product instance containing the signal
+                l1bkg: a L1Product instance containing the background
+
+                """
+        self.l1sig = l1sig
+        self.l1bkg = l1bkg
+
+        dmask = self.l1bkg.energy_bin_mask - self.l1sig.energy_bin_mask
+        if np.any(dmask < 0):
+            logger.error(
+                'Background subtraction failed due to the background energy range does not cover the signal energy range  '
+            )
+            return
+
+        #mean_pixel_rate_clip = self.l1bkg.mean_pixel_rate_spectra * self.l1sig.inverse_energy_bin_mask
+
+        self.pixel_bkg_counts = np.array([
+            int_time * self.l1bkg.mean_pixel_rate_spectra
+            for int_time in self.l1sig.timedel
+        ])
+        # set counts beyond the signal energy range to 0
+        self.subtracted_counts = (self.l1sig.counts - self.pixel_bkg_counts
+                                  ) * self.l1sig.inverse_energy_bin_mask
+
+        # Dead time correction needs to be included in the future
+        self.subtracted_counts_err = np.sqrt(
+            self.l1sig.counts + np.array([int_time * self.l1bkg.mean_pixel_rate_spectra_err ** 2 for int_time in self.l1sig.timedel])) * \
+            self.l1sig.inverse_energy_bin_mask
+        self.bkg_subtracted_spectrogram = np.sum(self.subtracted_counts,
+                                                 axis=(1, 2))
+
+    def peek(self):
+        fig, axs = plt.subplots(2, 2)
+        self.l1sig.peek(axs[0, 0])
+        self.l1bkg.peek(axs[0, 1])
+        X, Y = np.meshgrid(self.l1sig.time,
+                           np.arange(self.l1sig.min_ebin, self.l1sig.max_ebin))
+        im = axs[1, 0].pcolormesh(
+            X, Y,
+            np.transpose(
+                self.bkg_subtracted_spectrogram[:, self.l1sig.min_ebin:self.
+                                                l1sig.max_ebin]))
+        axs[1, 0].set_yticks(self.l1sig.energies['channel']
+                             [self.l1sig.min_ebin:self.l1sig.max_ebin:2])
+        axs[1, 0].set_yticklabels(
+            self.l1sig.energy_bin_names[self.l1sig.min_ebin:self.l1sig.
+                                        max_ebin:2])
+        fig = plt.gcf()
+        cbar = fig.colorbar(im, ax=axs[1, 0])
+        cbar.set_label('Counts')
+        axs[1, 0].set_title('Bkg sub. counts')
+        axs[1, 0].set_ylabel('Energy range(keV')
+        axs[1, 0].set_xlabel(f"Seconds since {self.l1sig.T0}s ")
+        axs[1, 1].plot(np.sum(self.l1sig.spectrogram, axis=0),
+                       drawstyle='steps-mid',
+                       label='Before subtraction')
+        axs[1, 1].plot(np.sum(self.bkg_subtracted_spectrogram, axis=0),
+                       drawstyle="steps-mid",
+                       label='After subtraction')
+        axs[1, 1].plot(np.sum(self.pixel_bkg_counts, axis=(0, 1, 2)),
+                       drawstyle="steps-mid",
+                       label='background')
+        axs[1, 1].legend()
+
+    def get_background_subtracted_spectrum(self, start_utc=None, end_utc=None):
+        """
+        Get signal background subtracted spectrum
+
+        """
+        start_unix = sdt.utc2unix(start_utc)
+        end_unix = sdt.utc2unix(end_utc)
+        start_time = start_unix - self.l1sig.T0_unix
+        end_time = end_unix - self.l1sig.T0_unix
+        start_i_tbin = np.argmax(
+            self.l1sig.time - 0.5 * self.l1sig.timedel >= start_time) if (
+                0 <= start_time <= self.l1sig.duration) else 0
+
+        end_i_tbin = np.argmin(
+            self.l1sig.time + 0.5 * self.l1sig.timedel <= end_time) if (
+                start_time <= end_time <= self.l1sig.duration) else len(
+                    self.l1sig.time)
+        time_span = self.l1sig.time[end_i_tbin] - self.l1sig.time[
+            start_i_tbin] + 0.5 * self.l1sig.timedel[
+                start_i_tbin] + 0.5 * self.l1sig.timedel[end_i_tbin]
+
+        bkg_sub_spectra = np.sum(
+            self.subtracted_counts[start_i_tbin:end_i_tbin, :, :, :],
+            axis=(0, 1, 2)) / time_span,
+        bkg_sub_spectra_err = np.sqrt(
+            np.sum(self.subtracted_counts_err[start_i_tbin:end_i_tbin, :, :, :]
+                   ** 2,
+                   axis=(0, 1, 2))) / time_span
+        return bkg_sub_spectra, bkg_sub_spectra_err
+
+

Methods

+
+
+def get_background_subtracted_spectrum(self, start_utc=None, end_utc=None) +
+
+

Get signal background subtracted spectrum

+
+ +Expand source code + +
def get_background_subtracted_spectrum(self, start_utc=None, end_utc=None):
+    """
+    Get signal background subtracted spectrum
+
+    """
+    start_unix = sdt.utc2unix(start_utc)
+    end_unix = sdt.utc2unix(end_utc)
+    start_time = start_unix - self.l1sig.T0_unix
+    end_time = end_unix - self.l1sig.T0_unix
+    start_i_tbin = np.argmax(
+        self.l1sig.time - 0.5 * self.l1sig.timedel >= start_time) if (
+            0 <= start_time <= self.l1sig.duration) else 0
+
+    end_i_tbin = np.argmin(
+        self.l1sig.time + 0.5 * self.l1sig.timedel <= end_time) if (
+            start_time <= end_time <= self.l1sig.duration) else len(
+                self.l1sig.time)
+    time_span = self.l1sig.time[end_i_tbin] - self.l1sig.time[
+        start_i_tbin] + 0.5 * self.l1sig.timedel[
+            start_i_tbin] + 0.5 * self.l1sig.timedel[end_i_tbin]
+
+    bkg_sub_spectra = np.sum(
+        self.subtracted_counts[start_i_tbin:end_i_tbin, :, :, :],
+        axis=(0, 1, 2)) / time_span,
+    bkg_sub_spectra_err = np.sqrt(
+        np.sum(self.subtracted_counts_err[start_i_tbin:end_i_tbin, :, :, :]
+               ** 2,
+               axis=(0, 1, 2))) / time_span
+    return bkg_sub_spectra, bkg_sub_spectra_err
+
+
+
+def peek(self) +
+
+
+
+ +Expand source code + +
def peek(self):
+    fig, axs = plt.subplots(2, 2)
+    self.l1sig.peek(axs[0, 0])
+    self.l1bkg.peek(axs[0, 1])
+    X, Y = np.meshgrid(self.l1sig.time,
+                       np.arange(self.l1sig.min_ebin, self.l1sig.max_ebin))
+    im = axs[1, 0].pcolormesh(
+        X, Y,
+        np.transpose(
+            self.bkg_subtracted_spectrogram[:, self.l1sig.min_ebin:self.
+                                            l1sig.max_ebin]))
+    axs[1, 0].set_yticks(self.l1sig.energies['channel']
+                         [self.l1sig.min_ebin:self.l1sig.max_ebin:2])
+    axs[1, 0].set_yticklabels(
+        self.l1sig.energy_bin_names[self.l1sig.min_ebin:self.l1sig.
+                                    max_ebin:2])
+    fig = plt.gcf()
+    cbar = fig.colorbar(im, ax=axs[1, 0])
+    cbar.set_label('Counts')
+    axs[1, 0].set_title('Bkg sub. counts')
+    axs[1, 0].set_ylabel('Energy range(keV')
+    axs[1, 0].set_xlabel(f"Seconds since {self.l1sig.T0}s ")
+    axs[1, 1].plot(np.sum(self.l1sig.spectrogram, axis=0),
+                   drawstyle='steps-mid',
+                   label='Before subtraction')
+    axs[1, 1].plot(np.sum(self.bkg_subtracted_spectrogram, axis=0),
+                   drawstyle="steps-mid",
+                   label='After subtraction')
+    axs[1, 1].plot(np.sum(self.pixel_bkg_counts, axis=(0, 1, 2)),
+                   drawstyle="steps-mid",
+                   label='background')
+    axs[1, 1].legend()
+
+
+
+
+
+class LiveTimeCorrection +
+
+
+
+ +Expand source code + +
class LiveTimeCorrection(object):
+    pass
+    """
+    #counts is np.array   time_bins, detector, pixel, energy bins
+    trigger_rates=l1data['triggers'][1:,:]/l1data['timedel'][:-1,None]
+    # delta time is off by 1 time bin due a bug in the
+    out=np.copy(trigger_rates)
+    tau=11e-6
+    live_time=1 - tau*trig
+    photo_in=trig/(live_time)
+        """
+
+    @classmethod
+    def L1_live_time_correction(cls, triggers, counts_arr, time_bins):
+        """ Live time correction
+        Args
+            triggers: ndarray
+                triggers in the spectrogram
+            counts_arr:ndarray
+                counts in the spectrogram
+            time_bins: ndarray
+                time_bins in the spectrogram
+        Returns
+        live_time_ratio: ndarray
+            live time ratio of detectors
+        count_rate:
+            corrected count rate
+        photons_in:
+            rate of photons illuminating the detector group
+
+        """
+
+        fpga_tau=10.1e-6
+        asic_tau=2.63e-6
+        trig_tau = fpga_tau+asic_tau
+
+        time_bins = time_bins[:, None]
+        photons_in = triggers/(time_bins-trig_tau*triggers)
+        #photon rate calculated using triggers 
+
+        correction_factors= np.zeros((time_bins.size, 32))
+        time_bins = time_bins[:, :, None, None]
+
+        time_bins = time_bins[:, :, None, None]
+        count_rates = counts_arr/time_bins
+        # print(counts_arr.shape)
+        for det in range(32):
+            trig_idx=inst.detector_id_to_trigger_index[det]
+            nin=photons_in[:,trig_idx]
+            cor_factor=0.94
+            live_ratio[:,det]=np.exp(- cor_factor*nin*asic_tau*1e-6)/(1+ nin*trig_tau)
+
+        return correction_factors, corrected_rates , count_rates,photons_in
+
+

Static methods

+
+
+def L1_live_time_correction(triggers, counts_arr, time_bins) +
+
+

Live time correction +Args +triggers: ndarray +triggers in the spectrogram +counts_arr:ndarray +counts in the spectrogram +time_bins: ndarray +time_bins in the spectrogram +Returns +live_time_ratio: ndarray +live time ratio of detectors +count_rate: +corrected count rate +photons_in: +rate of photons illuminating the detector group

+
+ +Expand source code + +
@classmethod
+def L1_live_time_correction(cls, triggers, counts_arr, time_bins):
+    """ Live time correction
+    Args
+        triggers: ndarray
+            triggers in the spectrogram
+        counts_arr:ndarray
+            counts in the spectrogram
+        time_bins: ndarray
+            time_bins in the spectrogram
+    Returns
+    live_time_ratio: ndarray
+        live time ratio of detectors
+    count_rate:
+        corrected count rate
+    photons_in:
+        rate of photons illuminating the detector group
+
+    """
+
+    fpga_tau=10.1e-6
+    asic_tau=2.63e-6
+    trig_tau = fpga_tau+asic_tau
+
+    time_bins = time_bins[:, None]
+    photons_in = triggers/(time_bins-trig_tau*triggers)
+    #photon rate calculated using triggers 
+
+    correction_factors= np.zeros((time_bins.size, 32))
+    time_bins = time_bins[:, :, None, None]
+
+    time_bins = time_bins[:, :, None, None]
+    count_rates = counts_arr/time_bins
+    # print(counts_arr.shape)
+    for det in range(32):
+        trig_idx=inst.detector_id_to_trigger_index[det]
+        nin=photons_in[:,trig_idx]
+        cor_factor=0.94
+        live_ratio[:,det]=np.exp(- cor_factor*nin*asic_tau*1e-6)/(1+ nin*trig_tau)
+
+    return correction_factors, corrected_rates , count_rates,photons_in
+
+
+
+
+
+class TransmissionCorrection +
+
+
+
+ +Expand source code + +
class TransmissionCorrection(object):
+    pass
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/detector_view.html b/docs/stixdcpy/detector_view.html new file mode 100644 index 0000000..704c1e4 --- /dev/null +++ b/docs/stixdcpy/detector_view.html @@ -0,0 +1,877 @@ + + + + + + +stixdcpy.detector_view API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.detector_view

+
+
+
+ +Expand source code + +
#!/usr/bin/python3
+#create STIX detector view plot
+# Author: Hualin Xiao
+# date: Dec 17, 2021
+import numpy as np
+from matplotlib import pyplot as plt
+
+
+class DetectorView(object):
+    CANVAS_W = 1005
+    CANVAS_H = 1105
+    VIEW_W = int(3 * CANVAS_W)
+    VIEW_H = int(3 * CANVAS_H)
+    VIEWBOX = f'0  0 {VIEW_W} {VIEW_H}'
+    RFRAME = 450
+    RASPECT = 70
+    P0 = np.array([CANVAS_W / 2., CANVAS_H - RFRAME - 5])
+    WHITE = 'rgb(255,255,255)'
+
+    def __init__(self,
+                 pixel_counts=np.zeros(384),
+                 cmap='viridis',
+                 colorbar=False,
+                 logscale=False):
+        """
+         Plot STIX detector
+         Parameters
+          pixel_counts: 1d np.array
+            
+            counts in 384 pixels
+          cmap:  str, optional
+            matploat colormap, for example viridis, plasma, etc.
+          colorbar: bool
+            Plot colobar if it is True 
+         Returns
+           python object
+
+        """
+        self.cmap_name = cmap
+        self.pixel_counts = pixel_counts
+        col = (np.array(plt.get_cmap(cmap).colors) * 256).astype(int)
+        self.color_map = [f'rgb({x[0]},{x[1]},{x[2]})' for x in col]
+        self.color_x = np.linspace(0, 1, len(self.color_map))
+
+        self.colors = [self.WHITE] * 384
+
+        self.vis_counts = pixel_counts if not logscale else np.log(
+            pixel_counts,
+            where=np.array(pixel_counts) > 0,
+            out=np.zeros_like(pixel_counts))
+        if np.max(self.vis_counts) > 0:
+            max_val = np.max(self.vis_counts)
+            min_val = np.min(self.vis_counts)
+            if max_val > min_val:
+                nx = (self.vis_counts - min_val) / (max_val - min_val)
+                self.colors = np.array([
+                    self.color_map[np.argmin(np.abs(y - self.color_x))]
+                    for y in nx
+                ])
+        self.svg = self.create_detector_svg(colorbar)
+        self.html = f'<div style="width:400px;height:400px;">{self.svg}</html>'
+
+    def get_html(self):
+        return self.html
+
+    def get_svg(self):
+        """
+        get svg string
+        """
+        return self.svg
+
+    def save(self, filename):
+        """
+            save detector view to a svg file
+        Parameters:
+          filename: str
+            svg filename
+        Returns None
+        """
+        with open(filename, 'w') as f:
+            f.write(self.svg)
+
+    def plot_in_notebook(self):
+        """
+         Plot detector in nootbook
+        """
+        from IPython.display import SVG
+        SVG(self.svg)
+
+    def _create_color_bar(self, x0, y0, width, height):
+        path = (
+            '<rect x="{x0}" y="{y0}" width="{width}" height="{height}"'
+            'style="fill:rgb(250,250,250); stroke-width:0;stroke:rgb(0,0,255)" />'
+        ).format(x0=x0, y0=y0, width=width, height=height)
+        num = len(self.color_map)
+        dl = width / num
+        max_value = np.max(self.pixel_counts)
+        for i, col in enumerate(self.color_map):
+            x = dl * i + x0
+            y = y0
+            path += '<rect x="{}" y="{}" width="{}" height="{}"  style="fill:{}; stroke-width:1;stroke:{}" />'.format(
+                x, y, dl, height, col, col)
+        num_ticks = 10
+        for i in range(0, num_ticks):
+            x = dl * i + x0
+            y = y0 - 20
+            path += '<text x="{}" y="{}" > {} </text>'.format(
+                x, y, max_value * i / num_ticks)
+
+        return path
+
+    def create_detector_svg(self, colorbar=True):
+        positions = [[135, 412.5], [135, 527.5], [135, 662.5], [135, 777.5],
+                     [260, 297.5], [260, 412.5], [260, 527.5], [260, 662.5],
+                     [260, 777.5], [260, 892.5], [385, 227.5], [385, 342.5],
+                     [385, 457.5], [385, 732.5], [385, 847.5], [385, 962.5],
+                     [510, 227.5], [510, 342.5], [510, 457.5], [510, 732.5],
+                     [510, 847.5], [510, 962.5], [635, 297.5], [635, 412.5],
+                     [635, 527.5], [635, 662.5], [635, 777.5], [635, 892.5],
+                     [760, 412.5], [760, 527.5], [760, 662.5], [760, 777.5]]
+        svg_start = '''
+            <svg width="{cw}" height="{ch}" viewBox="{view_box}">
+          <circle
+              style="opacity:0.1;fill:#0000ff;stroke:#0000ff;stroke-width:1.046;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+             id="path5200"
+             cx="{x0}"
+             cy="{y0}"
+             r="{r_frame}"/>
+          <path  style="stroke-width:3;stroke:rgb(0,0,250)"  d="M{x0} {y_min} L{x0} {y_max} " />
+          <path  style="stroke-width:3;stroke:rgb(0,0,250)"  d="M{x_min} {y0} L{x_max} {y0}" />
+      <circle
+         style="opacity:0.95999995;fill:#222b00;stroke:#0000ff;stroke-width:1.046;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="path5204"
+         cx="{x0}"
+         cy="{y0}"
+         r="{r_aspect}" />
+          '''.format(cw=self.CANVAS_W,
+                     ch=self.CANVAS_H,
+                     view_box=self.VIEWBOX,
+                     x0=self.P0[0],
+                     y0=self.P0[1],
+                     y_min=self.P0[1] - self.RFRAME,
+                     r_frame=self.RFRAME,
+                     r_aspect=self.RASPECT,
+                     y_max=self.P0[1] + self.RFRAME,
+                     x_min=self.P0[0] - self.RFRAME,
+                     x_max=self.P0[0] + self.RFRAME)
+
+        svg_end = '   </svg>'
+
+        color_bar = ''
+        if colorbar:
+            color_bar = self._create_color_bar(10, 100, 1000, 30)
+        template = svg_start + color_bar + '{}' + svg_end
+        items = []
+        for i, pos in enumerate(positions):
+            pos[1] = pos[1] + 5
+            items.append(self.create_one_detector_svg(i, pos, '{}'))
+
+        return template.format('\n'.join(items))
+
+    def create_one_detector_svg(self,
+                                detector_id=0,
+                                start=(0, 0),
+                                svg_template=''):
+        """ data is a 32*12 array """
+
+        if not svg_template:
+            svg_template = """
+            <svg width="110" height="110">
+            {}
+            </svg>
+            """
+        group = ''
+
+        pixel_template = '''
+          <path id="{}" text="" style="fill:{};stroke-width:1;stroke:rgb(200,200,200)"
+          d="{}" ><title>{}</title></path>'''
+
+        start_x = start[0]
+        start_y = start[1]
+        offset = np.array([start_x, start_y])
+        fill_color = 'rgb(230,230,230)'
+
+        pitch_x = 22
+        pitch_y = 46
+
+        big_p0_top = offset + np.array([6, 4])
+        big_p0_bottom = offset + np.array([6, 4 + 92])
+
+        big_pixel_top = 'h 22 v 46 h -11 v -4.5 h -11 Z'
+        big_pixel_bottom = 'h 22 v -46 h -11 v 4.5 h -11 Z'
+
+        small_p0 = offset + np.array([6, 50 - 4.5])
+        small_pixel_path = 'h 11 v 9 h -11  Z'
+
+        container = []
+        #create big pixels
+
+        guardring = '<rect x="{}" y="{}" width="100" height="100"  style="fill:rgb(255,255,255);stroke-width:1;stroke:rgb(0,0,0)" />'.format(
+            offset[0], offset[1])
+        x0 = offset[0]
+        y0 = offset[1]
+        #print("'det_{}':'M{} {} L {} {} L{} {} L{} {} Z ',".format(detector_id,x0,y0,x0+100,y0,x0+100,y0+100, x0,y0+100))
+        container.append(guardring)
+        text = '<text x="{}" y="{}" filled="red"> #{} </text>'.format(
+            offset[0] + 40, offset[1] + 110, detector_id + 1)
+        container.append(text)
+
+        for i in range(0, 4):
+            start = big_p0_top + np.array([i * pitch_x, 0])
+            path = 'M {} {} {}'.format(start[0], start[1], big_pixel_top)
+            pid = 'id-{}-{}'.format(detector_id, i)
+            pid = detector_id * 12 + i
+            counts = self.pixel_counts[pid]
+            fill_color = self.colors[pid]
+
+            container.append(
+                pixel_template.format(pid, fill_color, path, counts))
+
+        for i in range(0, 4):
+            start = big_p0_bottom + np.array([i * pitch_x, 0])
+            path = 'M {} {} {}'.format(start[0], start[1], big_pixel_bottom)
+            pid = 'id-{}-{}'.format(detector_id, i + 4)
+            pid = detector_id * 12 + i + 4
+            counts = self.pixel_counts[pid]
+            fill_color = self.colors[pid]
+
+            container.append(
+                pixel_template.format(pid, fill_color, path, counts))
+
+        for i in range(0, 4):
+            start = small_p0 + np.array([i * pitch_x, 0])
+            path = 'M {} {} {}'.format(start[0], start[1], small_pixel_path)
+            pid = 'id-{}-{}'.format(detector_id, i + 8)
+            pid = detector_id * 12 + i + 8
+            counts = self.pixel_counts[pid]
+            fill_color = self.colors[pid]
+            container.append(
+                pixel_template.format(pid, fill_color, path, counts))
+        group = '<g> {} </g>'.format('\n'.join(container))
+        return svg_template.format(group)
+
+
+if __name__ == '__main__':
+    with open('detector.svg', 'w') as f:
+        data = np.arange(384)
+        det = DetectorView(data)
+        f.write(det.get_svg())
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class DetectorView +(pixel_counts=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., +0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]), cmap='viridis', colorbar=False, logscale=False) +
+
+

Plot STIX detector +Parameters +pixel_counts: 1d np.array

+

counts in 384 pixels +cmap: +str, optional +matploat colormap, for example viridis, plasma, etc. +colorbar: bool +Plot colobar if it is True +Returns +python object

+
+ +Expand source code + +
class DetectorView(object):
+    CANVAS_W = 1005
+    CANVAS_H = 1105
+    VIEW_W = int(3 * CANVAS_W)
+    VIEW_H = int(3 * CANVAS_H)
+    VIEWBOX = f'0  0 {VIEW_W} {VIEW_H}'
+    RFRAME = 450
+    RASPECT = 70
+    P0 = np.array([CANVAS_W / 2., CANVAS_H - RFRAME - 5])
+    WHITE = 'rgb(255,255,255)'
+
+    def __init__(self,
+                 pixel_counts=np.zeros(384),
+                 cmap='viridis',
+                 colorbar=False,
+                 logscale=False):
+        """
+         Plot STIX detector
+         Parameters
+          pixel_counts: 1d np.array
+            
+            counts in 384 pixels
+          cmap:  str, optional
+            matploat colormap, for example viridis, plasma, etc.
+          colorbar: bool
+            Plot colobar if it is True 
+         Returns
+           python object
+
+        """
+        self.cmap_name = cmap
+        self.pixel_counts = pixel_counts
+        col = (np.array(plt.get_cmap(cmap).colors) * 256).astype(int)
+        self.color_map = [f'rgb({x[0]},{x[1]},{x[2]})' for x in col]
+        self.color_x = np.linspace(0, 1, len(self.color_map))
+
+        self.colors = [self.WHITE] * 384
+
+        self.vis_counts = pixel_counts if not logscale else np.log(
+            pixel_counts,
+            where=np.array(pixel_counts) > 0,
+            out=np.zeros_like(pixel_counts))
+        if np.max(self.vis_counts) > 0:
+            max_val = np.max(self.vis_counts)
+            min_val = np.min(self.vis_counts)
+            if max_val > min_val:
+                nx = (self.vis_counts - min_val) / (max_val - min_val)
+                self.colors = np.array([
+                    self.color_map[np.argmin(np.abs(y - self.color_x))]
+                    for y in nx
+                ])
+        self.svg = self.create_detector_svg(colorbar)
+        self.html = f'<div style="width:400px;height:400px;">{self.svg}</html>'
+
+    def get_html(self):
+        return self.html
+
+    def get_svg(self):
+        """
+        get svg string
+        """
+        return self.svg
+
+    def save(self, filename):
+        """
+            save detector view to a svg file
+        Parameters:
+          filename: str
+            svg filename
+        Returns None
+        """
+        with open(filename, 'w') as f:
+            f.write(self.svg)
+
+    def plot_in_notebook(self):
+        """
+         Plot detector in nootbook
+        """
+        from IPython.display import SVG
+        SVG(self.svg)
+
+    def _create_color_bar(self, x0, y0, width, height):
+        path = (
+            '<rect x="{x0}" y="{y0}" width="{width}" height="{height}"'
+            'style="fill:rgb(250,250,250); stroke-width:0;stroke:rgb(0,0,255)" />'
+        ).format(x0=x0, y0=y0, width=width, height=height)
+        num = len(self.color_map)
+        dl = width / num
+        max_value = np.max(self.pixel_counts)
+        for i, col in enumerate(self.color_map):
+            x = dl * i + x0
+            y = y0
+            path += '<rect x="{}" y="{}" width="{}" height="{}"  style="fill:{}; stroke-width:1;stroke:{}" />'.format(
+                x, y, dl, height, col, col)
+        num_ticks = 10
+        for i in range(0, num_ticks):
+            x = dl * i + x0
+            y = y0 - 20
+            path += '<text x="{}" y="{}" > {} </text>'.format(
+                x, y, max_value * i / num_ticks)
+
+        return path
+
+    def create_detector_svg(self, colorbar=True):
+        positions = [[135, 412.5], [135, 527.5], [135, 662.5], [135, 777.5],
+                     [260, 297.5], [260, 412.5], [260, 527.5], [260, 662.5],
+                     [260, 777.5], [260, 892.5], [385, 227.5], [385, 342.5],
+                     [385, 457.5], [385, 732.5], [385, 847.5], [385, 962.5],
+                     [510, 227.5], [510, 342.5], [510, 457.5], [510, 732.5],
+                     [510, 847.5], [510, 962.5], [635, 297.5], [635, 412.5],
+                     [635, 527.5], [635, 662.5], [635, 777.5], [635, 892.5],
+                     [760, 412.5], [760, 527.5], [760, 662.5], [760, 777.5]]
+        svg_start = '''
+            <svg width="{cw}" height="{ch}" viewBox="{view_box}">
+          <circle
+              style="opacity:0.1;fill:#0000ff;stroke:#0000ff;stroke-width:1.046;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+             id="path5200"
+             cx="{x0}"
+             cy="{y0}"
+             r="{r_frame}"/>
+          <path  style="stroke-width:3;stroke:rgb(0,0,250)"  d="M{x0} {y_min} L{x0} {y_max} " />
+          <path  style="stroke-width:3;stroke:rgb(0,0,250)"  d="M{x_min} {y0} L{x_max} {y0}" />
+      <circle
+         style="opacity:0.95999995;fill:#222b00;stroke:#0000ff;stroke-width:1.046;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="path5204"
+         cx="{x0}"
+         cy="{y0}"
+         r="{r_aspect}" />
+          '''.format(cw=self.CANVAS_W,
+                     ch=self.CANVAS_H,
+                     view_box=self.VIEWBOX,
+                     x0=self.P0[0],
+                     y0=self.P0[1],
+                     y_min=self.P0[1] - self.RFRAME,
+                     r_frame=self.RFRAME,
+                     r_aspect=self.RASPECT,
+                     y_max=self.P0[1] + self.RFRAME,
+                     x_min=self.P0[0] - self.RFRAME,
+                     x_max=self.P0[0] + self.RFRAME)
+
+        svg_end = '   </svg>'
+
+        color_bar = ''
+        if colorbar:
+            color_bar = self._create_color_bar(10, 100, 1000, 30)
+        template = svg_start + color_bar + '{}' + svg_end
+        items = []
+        for i, pos in enumerate(positions):
+            pos[1] = pos[1] + 5
+            items.append(self.create_one_detector_svg(i, pos, '{}'))
+
+        return template.format('\n'.join(items))
+
+    def create_one_detector_svg(self,
+                                detector_id=0,
+                                start=(0, 0),
+                                svg_template=''):
+        """ data is a 32*12 array """
+
+        if not svg_template:
+            svg_template = """
+            <svg width="110" height="110">
+            {}
+            </svg>
+            """
+        group = ''
+
+        pixel_template = '''
+          <path id="{}" text="" style="fill:{};stroke-width:1;stroke:rgb(200,200,200)"
+          d="{}" ><title>{}</title></path>'''
+
+        start_x = start[0]
+        start_y = start[1]
+        offset = np.array([start_x, start_y])
+        fill_color = 'rgb(230,230,230)'
+
+        pitch_x = 22
+        pitch_y = 46
+
+        big_p0_top = offset + np.array([6, 4])
+        big_p0_bottom = offset + np.array([6, 4 + 92])
+
+        big_pixel_top = 'h 22 v 46 h -11 v -4.5 h -11 Z'
+        big_pixel_bottom = 'h 22 v -46 h -11 v 4.5 h -11 Z'
+
+        small_p0 = offset + np.array([6, 50 - 4.5])
+        small_pixel_path = 'h 11 v 9 h -11  Z'
+
+        container = []
+        #create big pixels
+
+        guardring = '<rect x="{}" y="{}" width="100" height="100"  style="fill:rgb(255,255,255);stroke-width:1;stroke:rgb(0,0,0)" />'.format(
+            offset[0], offset[1])
+        x0 = offset[0]
+        y0 = offset[1]
+        #print("'det_{}':'M{} {} L {} {} L{} {} L{} {} Z ',".format(detector_id,x0,y0,x0+100,y0,x0+100,y0+100, x0,y0+100))
+        container.append(guardring)
+        text = '<text x="{}" y="{}" filled="red"> #{} </text>'.format(
+            offset[0] + 40, offset[1] + 110, detector_id + 1)
+        container.append(text)
+
+        for i in range(0, 4):
+            start = big_p0_top + np.array([i * pitch_x, 0])
+            path = 'M {} {} {}'.format(start[0], start[1], big_pixel_top)
+            pid = 'id-{}-{}'.format(detector_id, i)
+            pid = detector_id * 12 + i
+            counts = self.pixel_counts[pid]
+            fill_color = self.colors[pid]
+
+            container.append(
+                pixel_template.format(pid, fill_color, path, counts))
+
+        for i in range(0, 4):
+            start = big_p0_bottom + np.array([i * pitch_x, 0])
+            path = 'M {} {} {}'.format(start[0], start[1], big_pixel_bottom)
+            pid = 'id-{}-{}'.format(detector_id, i + 4)
+            pid = detector_id * 12 + i + 4
+            counts = self.pixel_counts[pid]
+            fill_color = self.colors[pid]
+
+            container.append(
+                pixel_template.format(pid, fill_color, path, counts))
+
+        for i in range(0, 4):
+            start = small_p0 + np.array([i * pitch_x, 0])
+            path = 'M {} {} {}'.format(start[0], start[1], small_pixel_path)
+            pid = 'id-{}-{}'.format(detector_id, i + 8)
+            pid = detector_id * 12 + i + 8
+            counts = self.pixel_counts[pid]
+            fill_color = self.colors[pid]
+            container.append(
+                pixel_template.format(pid, fill_color, path, counts))
+        group = '<g> {} </g>'.format('\n'.join(container))
+        return svg_template.format(group)
+
+

Class variables

+
+
var CANVAS_H
+
+
+
+
var CANVAS_W
+
+
+
+
var P0
+
+
+
+
var RASPECT
+
+
+
+
var RFRAME
+
+
+
+
var VIEWBOX
+
+
+
+
var VIEW_H
+
+
+
+
var VIEW_W
+
+
+
+
var WHITE
+
+
+
+
+

Methods

+
+
+def create_detector_svg(self, colorbar=True) +
+
+
+
+ +Expand source code + +
def create_detector_svg(self, colorbar=True):
+    positions = [[135, 412.5], [135, 527.5], [135, 662.5], [135, 777.5],
+                 [260, 297.5], [260, 412.5], [260, 527.5], [260, 662.5],
+                 [260, 777.5], [260, 892.5], [385, 227.5], [385, 342.5],
+                 [385, 457.5], [385, 732.5], [385, 847.5], [385, 962.5],
+                 [510, 227.5], [510, 342.5], [510, 457.5], [510, 732.5],
+                 [510, 847.5], [510, 962.5], [635, 297.5], [635, 412.5],
+                 [635, 527.5], [635, 662.5], [635, 777.5], [635, 892.5],
+                 [760, 412.5], [760, 527.5], [760, 662.5], [760, 777.5]]
+    svg_start = '''
+        <svg width="{cw}" height="{ch}" viewBox="{view_box}">
+      <circle
+          style="opacity:0.1;fill:#0000ff;stroke:#0000ff;stroke-width:1.046;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="path5200"
+         cx="{x0}"
+         cy="{y0}"
+         r="{r_frame}"/>
+      <path  style="stroke-width:3;stroke:rgb(0,0,250)"  d="M{x0} {y_min} L{x0} {y_max} " />
+      <path  style="stroke-width:3;stroke:rgb(0,0,250)"  d="M{x_min} {y0} L{x_max} {y0}" />
+  <circle
+     style="opacity:0.95999995;fill:#222b00;stroke:#0000ff;stroke-width:1.046;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+     id="path5204"
+     cx="{x0}"
+     cy="{y0}"
+     r="{r_aspect}" />
+      '''.format(cw=self.CANVAS_W,
+                 ch=self.CANVAS_H,
+                 view_box=self.VIEWBOX,
+                 x0=self.P0[0],
+                 y0=self.P0[1],
+                 y_min=self.P0[1] - self.RFRAME,
+                 r_frame=self.RFRAME,
+                 r_aspect=self.RASPECT,
+                 y_max=self.P0[1] + self.RFRAME,
+                 x_min=self.P0[0] - self.RFRAME,
+                 x_max=self.P0[0] + self.RFRAME)
+
+    svg_end = '   </svg>'
+
+    color_bar = ''
+    if colorbar:
+        color_bar = self._create_color_bar(10, 100, 1000, 30)
+    template = svg_start + color_bar + '{}' + svg_end
+    items = []
+    for i, pos in enumerate(positions):
+        pos[1] = pos[1] + 5
+        items.append(self.create_one_detector_svg(i, pos, '{}'))
+
+    return template.format('\n'.join(items))
+
+
+
+def create_one_detector_svg(self, detector_id=0, start=(0, 0), svg_template='') +
+
+

data is a 32*12 array

+
+ +Expand source code + +
def create_one_detector_svg(self,
+                            detector_id=0,
+                            start=(0, 0),
+                            svg_template=''):
+    """ data is a 32*12 array """
+
+    if not svg_template:
+        svg_template = """
+        <svg width="110" height="110">
+        {}
+        </svg>
+        """
+    group = ''
+
+    pixel_template = '''
+      <path id="{}" text="" style="fill:{};stroke-width:1;stroke:rgb(200,200,200)"
+      d="{}" ><title>{}</title></path>'''
+
+    start_x = start[0]
+    start_y = start[1]
+    offset = np.array([start_x, start_y])
+    fill_color = 'rgb(230,230,230)'
+
+    pitch_x = 22
+    pitch_y = 46
+
+    big_p0_top = offset + np.array([6, 4])
+    big_p0_bottom = offset + np.array([6, 4 + 92])
+
+    big_pixel_top = 'h 22 v 46 h -11 v -4.5 h -11 Z'
+    big_pixel_bottom = 'h 22 v -46 h -11 v 4.5 h -11 Z'
+
+    small_p0 = offset + np.array([6, 50 - 4.5])
+    small_pixel_path = 'h 11 v 9 h -11  Z'
+
+    container = []
+    #create big pixels
+
+    guardring = '<rect x="{}" y="{}" width="100" height="100"  style="fill:rgb(255,255,255);stroke-width:1;stroke:rgb(0,0,0)" />'.format(
+        offset[0], offset[1])
+    x0 = offset[0]
+    y0 = offset[1]
+    #print("'det_{}':'M{} {} L {} {} L{} {} L{} {} Z ',".format(detector_id,x0,y0,x0+100,y0,x0+100,y0+100, x0,y0+100))
+    container.append(guardring)
+    text = '<text x="{}" y="{}" filled="red"> #{} </text>'.format(
+        offset[0] + 40, offset[1] + 110, detector_id + 1)
+    container.append(text)
+
+    for i in range(0, 4):
+        start = big_p0_top + np.array([i * pitch_x, 0])
+        path = 'M {} {} {}'.format(start[0], start[1], big_pixel_top)
+        pid = 'id-{}-{}'.format(detector_id, i)
+        pid = detector_id * 12 + i
+        counts = self.pixel_counts[pid]
+        fill_color = self.colors[pid]
+
+        container.append(
+            pixel_template.format(pid, fill_color, path, counts))
+
+    for i in range(0, 4):
+        start = big_p0_bottom + np.array([i * pitch_x, 0])
+        path = 'M {} {} {}'.format(start[0], start[1], big_pixel_bottom)
+        pid = 'id-{}-{}'.format(detector_id, i + 4)
+        pid = detector_id * 12 + i + 4
+        counts = self.pixel_counts[pid]
+        fill_color = self.colors[pid]
+
+        container.append(
+            pixel_template.format(pid, fill_color, path, counts))
+
+    for i in range(0, 4):
+        start = small_p0 + np.array([i * pitch_x, 0])
+        path = 'M {} {} {}'.format(start[0], start[1], small_pixel_path)
+        pid = 'id-{}-{}'.format(detector_id, i + 8)
+        pid = detector_id * 12 + i + 8
+        counts = self.pixel_counts[pid]
+        fill_color = self.colors[pid]
+        container.append(
+            pixel_template.format(pid, fill_color, path, counts))
+    group = '<g> {} </g>'.format('\n'.join(container))
+    return svg_template.format(group)
+
+
+
+def get_html(self) +
+
+
+
+ +Expand source code + +
def get_html(self):
+    return self.html
+
+
+
+def get_svg(self) +
+
+

get svg string

+
+ +Expand source code + +
def get_svg(self):
+    """
+    get svg string
+    """
+    return self.svg
+
+
+
+def plot_in_notebook(self) +
+
+

Plot detector in nootbook

+
+ +Expand source code + +
def plot_in_notebook(self):
+    """
+     Plot detector in nootbook
+    """
+    from IPython.display import SVG
+    SVG(self.svg)
+
+
+
+def save(self, filename) +
+
+

save detector view to a svg file

+

Parameters

+

filename: str +svg filename +Returns None

+
+ +Expand source code + +
def save(self, filename):
+    """
+        save detector view to a svg file
+    Parameters:
+      filename: str
+        svg filename
+    Returns None
+    """
+    with open(filename, 'w') as f:
+        f.write(self.svg)
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/energylut.html b/docs/stixdcpy/energylut.html new file mode 100644 index 0000000..2c7c08a --- /dev/null +++ b/docs/stixdcpy/energylut.html @@ -0,0 +1,569 @@ + + + + + + +stixdcpy.energylut API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.energylut

+
+
+

This script provides APIs to retrieve energy +calibration data from STIX data center +,and some tools to display the data +Author: Hualin Xiao (hualin.xiao@fhnw.ch) +Date: Sep. 1, 2021

+
+ +Expand source code + +
#!/usr/bin/python
+"""
+    This script provides APIs to retrieve energy  calibration data from STIX data center  ,and some tools to display the data
+    Author: Hualin Xiao (hualin.xiao@fhnw.ch)
+    Date: Sep. 1, 2021
+
+"""
+from pprint import pprint
+
+import numpy as np
+from stixdcpy.logger import logger
+from stixdcpy import io as sio
+from stixdcpy.net import JSONRequest as jreq
+from stixdcpy.transmission import Transmission
+
+
+class EnergyLUT(sio.IO):
+    def __init__(self, data):
+        self.data = data
+        self.tran = Transmission()
+
+    @classmethod
+    def request(cls, utc):
+        data = jreq.fetch_elut(utc)
+        '''
+        data structure
+        {'data':{
+                    'onboard':self.onboard_elut, 
+                    'calibration':self.calibration_run_elut,
+                    'true_energy_bin_edges':self.true_energy_bin_edges,
+                    'energy_bin_edges':NOMINAL_EBIN_EDGES,
+                },
+                'info': self.info(),
+                }
+                '''
+        return cls(data)
+
+    @classmethod
+    def from_npy(cls, filename):
+        with np.load(filename, allow_picke=True) as data:
+            elut_data = data.item()['elut']
+            cls(elut_data)
+
+    def save_npy(self, filename):
+        np.save(filename, {'elut': self.data})
+
+    def info(self):
+        try:
+            pprint(self.data['info'])
+            # pprint('Pixel 0 true energy bin  edges: ')
+            # pprint(self.get_pixel_true_ebins(0))
+            # pprint('...')
+
+        except KeyError as e:
+            logger.error(e)
+
+    def __getattr__(self, name):
+        if name == 'data':
+            return self.data['data']
+
+    def get_data(self):
+        return self.data['data']
+
+    def get_calibration_data(self):
+        """Get calibration data
+
+        Returns:
+            result: dict, or None
+                Calibration data python dictionary if success or None if failed 
+        """
+        try:
+            return self.data['data']['calibration']
+        except Exception as e:
+            print(e)
+            return None
+
+    def get_onboard_elut(self):
+        try:
+            return self.data['data']['onboard']
+        except (KeyError, TypeError):
+            logger.error('Failed to retrieve onboard elut!')
+            return None
+
+    def get_pixel_true_ebins(self, pixel):
+        """Get the real energy bin ranges for the given pixel
+
+        Args:
+            pixel (int): pixel ID ranging from 0...383
+
+        Returns:
+            ebins: numpy.array
+                Lower and upper bounds of 32 energy bins
+        """        
+        true_ebins = np.array(self.data['data']['true_energy_bin_edges'])
+        pixel_ebins = true_ebins[:, pixel]  # 33 x 384 retrieve the column
+        ebins = np.column_stack((pixel_ebins[:-1], pixel_ebins[1:]))
+        return ebins
+
+    def get_pixel_ebins_transmissions(self):
+        """
+        Get transmission for pixels at a given time
+        Args: 
+            None
+        Returns:
+            A numpy array with a shape of 32 x12 x 32.  The three dimensions indicate detector, pixel, and transmission for 32 energy channels.
+            The transmission for the last energy bin set to 0
+            """
+        true_ebins = np.array(
+            self.data['data']
+            ['true_energy_bin_edges'])  # an 2d array: 33 x 384
+        trans = np.zeros((32, 12, 32))
+        for i in range(32):
+            for j in range(12):
+                ipix = i * 12 + j
+                pixel_ebins = true_ebins[:, ipix]  # retrieve the column
+                ebins = np.column_stack((pixel_ebins[:-1], pixel_ebins[1:]))
+                ebins[0][0] = np.finfo(float).eps
+                ebins[31][1] = 300
+
+                trans[i][j] = self.tran.get_detector_transmission(
+                    i, ebins, attenuator=False)
+        trans[:, :,
+              31] = 0  # set the transmission for the last energy bin to 0
+        trans[:, :,
+              0] = 0  # set the transmission for the first energy bin to 0
+        return trans
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class EnergyLUT +(data) +
+
+

Base object

+
+ +Expand source code + +
class EnergyLUT(sio.IO):
+    def __init__(self, data):
+        self.data = data
+        self.tran = Transmission()
+
+    @classmethod
+    def request(cls, utc):
+        data = jreq.fetch_elut(utc)
+        '''
+        data structure
+        {'data':{
+                    'onboard':self.onboard_elut, 
+                    'calibration':self.calibration_run_elut,
+                    'true_energy_bin_edges':self.true_energy_bin_edges,
+                    'energy_bin_edges':NOMINAL_EBIN_EDGES,
+                },
+                'info': self.info(),
+                }
+                '''
+        return cls(data)
+
+    @classmethod
+    def from_npy(cls, filename):
+        with np.load(filename, allow_picke=True) as data:
+            elut_data = data.item()['elut']
+            cls(elut_data)
+
+    def save_npy(self, filename):
+        np.save(filename, {'elut': self.data})
+
+    def info(self):
+        try:
+            pprint(self.data['info'])
+            # pprint('Pixel 0 true energy bin  edges: ')
+            # pprint(self.get_pixel_true_ebins(0))
+            # pprint('...')
+
+        except KeyError as e:
+            logger.error(e)
+
+    def __getattr__(self, name):
+        if name == 'data':
+            return self.data['data']
+
+    def get_data(self):
+        return self.data['data']
+
+    def get_calibration_data(self):
+        """Get calibration data
+
+        Returns:
+            result: dict, or None
+                Calibration data python dictionary if success or None if failed 
+        """
+        try:
+            return self.data['data']['calibration']
+        except Exception as e:
+            print(e)
+            return None
+
+    def get_onboard_elut(self):
+        try:
+            return self.data['data']['onboard']
+        except (KeyError, TypeError):
+            logger.error('Failed to retrieve onboard elut!')
+            return None
+
+    def get_pixel_true_ebins(self, pixel):
+        """Get the real energy bin ranges for the given pixel
+
+        Args:
+            pixel (int): pixel ID ranging from 0...383
+
+        Returns:
+            ebins: numpy.array
+                Lower and upper bounds of 32 energy bins
+        """        
+        true_ebins = np.array(self.data['data']['true_energy_bin_edges'])
+        pixel_ebins = true_ebins[:, pixel]  # 33 x 384 retrieve the column
+        ebins = np.column_stack((pixel_ebins[:-1], pixel_ebins[1:]))
+        return ebins
+
+    def get_pixel_ebins_transmissions(self):
+        """
+        Get transmission for pixels at a given time
+        Args: 
+            None
+        Returns:
+            A numpy array with a shape of 32 x12 x 32.  The three dimensions indicate detector, pixel, and transmission for 32 energy channels.
+            The transmission for the last energy bin set to 0
+            """
+        true_ebins = np.array(
+            self.data['data']
+            ['true_energy_bin_edges'])  # an 2d array: 33 x 384
+        trans = np.zeros((32, 12, 32))
+        for i in range(32):
+            for j in range(12):
+                ipix = i * 12 + j
+                pixel_ebins = true_ebins[:, ipix]  # retrieve the column
+                ebins = np.column_stack((pixel_ebins[:-1], pixel_ebins[1:]))
+                ebins[0][0] = np.finfo(float).eps
+                ebins[31][1] = 300
+
+                trans[i][j] = self.tran.get_detector_transmission(
+                    i, ebins, attenuator=False)
+        trans[:, :,
+              31] = 0  # set the transmission for the last energy bin to 0
+        trans[:, :,
+              0] = 0  # set the transmission for the first energy bin to 0
+        return trans
+
+

Ancestors

+ +

Static methods

+
+
+def from_npy(filename) +
+
+
+
+ +Expand source code + +
@classmethod
+def from_npy(cls, filename):
+    with np.load(filename, allow_picke=True) as data:
+        elut_data = data.item()['elut']
+        cls(elut_data)
+
+
+
+def request(utc) +
+
+
+
+ +Expand source code + +
@classmethod
+def request(cls, utc):
+    data = jreq.fetch_elut(utc)
+    '''
+    data structure
+    {'data':{
+                'onboard':self.onboard_elut, 
+                'calibration':self.calibration_run_elut,
+                'true_energy_bin_edges':self.true_energy_bin_edges,
+                'energy_bin_edges':NOMINAL_EBIN_EDGES,
+            },
+            'info': self.info(),
+            }
+            '''
+    return cls(data)
+
+
+
+

Methods

+
+
+def get_calibration_data(self) +
+
+

Get calibration data

+

Returns

+
+
result
+
dict, or None +Calibration data python dictionary if success or None if failed
+
+
+ +Expand source code + +
def get_calibration_data(self):
+    """Get calibration data
+
+    Returns:
+        result: dict, or None
+            Calibration data python dictionary if success or None if failed 
+    """
+    try:
+        return self.data['data']['calibration']
+    except Exception as e:
+        print(e)
+        return None
+
+
+
+def get_data(self) +
+
+
+
+ +Expand source code + +
def get_data(self):
+    return self.data['data']
+
+
+
+def get_onboard_elut(self) +
+
+
+
+ +Expand source code + +
def get_onboard_elut(self):
+    try:
+        return self.data['data']['onboard']
+    except (KeyError, TypeError):
+        logger.error('Failed to retrieve onboard elut!')
+        return None
+
+
+
+def get_pixel_ebins_transmissions(self) +
+
+

Get transmission for pixels at a given time +Args: +None

+

Returns

+

A numpy array with a shape of 32 x12 x 32. +The three dimensions indicate detector, pixel, and transmission for 32 energy channels. +The transmission for the last energy bin set to 0

+
+ +Expand source code + +
def get_pixel_ebins_transmissions(self):
+    """
+    Get transmission for pixels at a given time
+    Args: 
+        None
+    Returns:
+        A numpy array with a shape of 32 x12 x 32.  The three dimensions indicate detector, pixel, and transmission for 32 energy channels.
+        The transmission for the last energy bin set to 0
+        """
+    true_ebins = np.array(
+        self.data['data']
+        ['true_energy_bin_edges'])  # an 2d array: 33 x 384
+    trans = np.zeros((32, 12, 32))
+    for i in range(32):
+        for j in range(12):
+            ipix = i * 12 + j
+            pixel_ebins = true_ebins[:, ipix]  # retrieve the column
+            ebins = np.column_stack((pixel_ebins[:-1], pixel_ebins[1:]))
+            ebins[0][0] = np.finfo(float).eps
+            ebins[31][1] = 300
+
+            trans[i][j] = self.tran.get_detector_transmission(
+                i, ebins, attenuator=False)
+    trans[:, :,
+          31] = 0  # set the transmission for the last energy bin to 0
+    trans[:, :,
+          0] = 0  # set the transmission for the first energy bin to 0
+    return trans
+
+
+
+def get_pixel_true_ebins(self, pixel) +
+
+

Get the real energy bin ranges for the given pixel

+

Args

+
+
pixel : int
+
pixel ID ranging from 0…383
+
+

Returns

+
+
ebins
+
numpy.array +Lower and upper bounds of 32 energy bins
+
+
+ +Expand source code + +
def get_pixel_true_ebins(self, pixel):
+    """Get the real energy bin ranges for the given pixel
+
+    Args:
+        pixel (int): pixel ID ranging from 0...383
+
+    Returns:
+        ebins: numpy.array
+            Lower and upper bounds of 32 energy bins
+    """        
+    true_ebins = np.array(self.data['data']['true_energy_bin_edges'])
+    pixel_ebins = true_ebins[:, pixel]  # 33 x 384 retrieve the column
+    ebins = np.column_stack((pixel_ebins[:-1], pixel_ebins[1:]))
+    return ebins
+
+
+
+def info(self) +
+
+
+
+ +Expand source code + +
def info(self):
+    try:
+        pprint(self.data['info'])
+        # pprint('Pixel 0 true energy bin  edges: ')
+        # pprint(self.get_pixel_true_ebins(0))
+        # pprint('...')
+
+    except KeyError as e:
+        logger.error(e)
+
+
+
+def save_npy(self, filename) +
+
+
+
+ +Expand source code + +
def save_npy(self, filename):
+    np.save(filename, {'elut': self.data})
+
+
+
+

Inherited members

+ +
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/housekeeping.html b/docs/stixdcpy/housekeeping.html new file mode 100644 index 0000000..3b3031d --- /dev/null +++ b/docs/stixdcpy/housekeeping.html @@ -0,0 +1,362 @@ + + + + + + +stixdcpy.housekeeping API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.housekeeping

+
+
+

This module provides APIs to retrieve Housekeeping data from STIX data center +,and some tools to display the data +Author: Hualin Xiao (hualin.xiao@fhnw.ch) +Date: Sep. 1, 2021

+
+ +Expand source code + +
#!/usr/bin/python
+
+"""
+    This module provides APIs to retrieve Housekeeping data from STIX data center  ,and some tools to display the data
+    Author: Hualin Xiao (hualin.xiao@fhnw.ch)
+    Date: Sep. 1, 2021
+
+"""
+import pandas as pd
+from astropy.io import fits
+from matplotlib import pyplot as plt
+
+from stixdcpy import io as sio
+from stixdcpy import time as sdt
+from stixdcpy.net import JSONRequest as jreq
+
+
+class Housekeeping(sio.IO):
+    def __init__(self, data):
+        data['datetime'] = [sdt.utc2datetime(x) for x in data['time']]
+        self.data = data
+        self.param_names = self.data['names']
+
+    @classmethod
+    def from_sdc(cls, start_utc: str, end_utc: str):
+        """
+            Fetch housekeeping data from server
+            Parameters
+            start_utc: str
+                data start time 
+            end_utc: str
+                data end time 
+            Returns:
+            housekeeping data object
+
+        """
+        data = jreq.fetch_housekeeping(start_utc, end_utc)
+        return cls(data)
+
+    def plot(self, parameters, which='eng', ax=None):
+        """
+        Plot a housekeeping parameter
+        Parameters
+        param: str
+          parameter name
+        which: str
+          what parameter to plot. It can be 'raw' or 'eng'
+        ax: matplotlib axes, optional
+          a plot will be created if it is not specified
+        Returns:
+        ax:  matplotlib axes
+        """
+        params = parameters.split(',')
+        if not ax:
+            _, ax = plt.subplots()
+        key = 'raw_values' if which == 'raw' else 'eng_values'
+        for param in params:
+            if param not in self.data[key]:
+                raise KeyError('Invalid housekeeping parameter name')
+            ax.plot(self.data['datetime'],
+                    self.data[key][param],
+                    label=self.data['names'].get(param, ''))
+        ax.set_xlabel('UTC')
+        ax.set_ylabel('Value')
+        return ax
+
+    def __getattr__(self, name):
+        if name == 'data':
+            return self.data
+
+    def get_data(self):
+        return self.data
+
+    def peek(self, ax=None, legend_loc='upper right'):
+        if not ax:
+            _, ax = plt.subplots()
+        ax.plot(self.data['datetime'], self.data['eng_values']['NIX00081'])
+        ax.set_title(self.data['names']['NIX00081'])
+        return ax
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class Housekeeping +(data) +
+
+

Base object

+
+ +Expand source code + +
class Housekeeping(sio.IO):
+    def __init__(self, data):
+        data['datetime'] = [sdt.utc2datetime(x) for x in data['time']]
+        self.data = data
+        self.param_names = self.data['names']
+
+    @classmethod
+    def from_sdc(cls, start_utc: str, end_utc: str):
+        """
+            Fetch housekeeping data from server
+            Parameters
+            start_utc: str
+                data start time 
+            end_utc: str
+                data end time 
+            Returns:
+            housekeeping data object
+
+        """
+        data = jreq.fetch_housekeeping(start_utc, end_utc)
+        return cls(data)
+
+    def plot(self, parameters, which='eng', ax=None):
+        """
+        Plot a housekeeping parameter
+        Parameters
+        param: str
+          parameter name
+        which: str
+          what parameter to plot. It can be 'raw' or 'eng'
+        ax: matplotlib axes, optional
+          a plot will be created if it is not specified
+        Returns:
+        ax:  matplotlib axes
+        """
+        params = parameters.split(',')
+        if not ax:
+            _, ax = plt.subplots()
+        key = 'raw_values' if which == 'raw' else 'eng_values'
+        for param in params:
+            if param not in self.data[key]:
+                raise KeyError('Invalid housekeeping parameter name')
+            ax.plot(self.data['datetime'],
+                    self.data[key][param],
+                    label=self.data['names'].get(param, ''))
+        ax.set_xlabel('UTC')
+        ax.set_ylabel('Value')
+        return ax
+
+    def __getattr__(self, name):
+        if name == 'data':
+            return self.data
+
+    def get_data(self):
+        return self.data
+
+    def peek(self, ax=None, legend_loc='upper right'):
+        if not ax:
+            _, ax = plt.subplots()
+        ax.plot(self.data['datetime'], self.data['eng_values']['NIX00081'])
+        ax.set_title(self.data['names']['NIX00081'])
+        return ax
+
+

Ancestors

+ +

Static methods

+
+
+def from_sdc(start_utc: str, end_utc: str) +
+
+

Fetch housekeeping data from server +Parameters +start_utc: str +data start time +end_utc: str +data end time +Returns: +housekeeping data object

+
+ +Expand source code + +
@classmethod
+def from_sdc(cls, start_utc: str, end_utc: str):
+    """
+        Fetch housekeeping data from server
+        Parameters
+        start_utc: str
+            data start time 
+        end_utc: str
+            data end time 
+        Returns:
+        housekeeping data object
+
+    """
+    data = jreq.fetch_housekeeping(start_utc, end_utc)
+    return cls(data)
+
+
+
+

Methods

+
+
+def get_data(self) +
+
+
+
+ +Expand source code + +
def get_data(self):
+    return self.data
+
+
+
+def peek(self, ax=None, legend_loc='upper right') +
+
+
+
+ +Expand source code + +
def peek(self, ax=None, legend_loc='upper right'):
+    if not ax:
+        _, ax = plt.subplots()
+    ax.plot(self.data['datetime'], self.data['eng_values']['NIX00081'])
+    ax.set_title(self.data['names']['NIX00081'])
+    return ax
+
+
+
+def plot(self, parameters, which='eng', ax=None) +
+
+

Plot a housekeeping parameter +Parameters +param: str +parameter name +which: str +what parameter to plot. It can be 'raw' or 'eng' +ax: matplotlib axes, optional +a plot will be created if it is not specified +Returns: +ax: +matplotlib axes

+
+ +Expand source code + +
def plot(self, parameters, which='eng', ax=None):
+    """
+    Plot a housekeeping parameter
+    Parameters
+    param: str
+      parameter name
+    which: str
+      what parameter to plot. It can be 'raw' or 'eng'
+    ax: matplotlib axes, optional
+      a plot will be created if it is not specified
+    Returns:
+    ax:  matplotlib axes
+    """
+    params = parameters.split(',')
+    if not ax:
+        _, ax = plt.subplots()
+    key = 'raw_values' if which == 'raw' else 'eng_values'
+    for param in params:
+        if param not in self.data[key]:
+            raise KeyError('Invalid housekeeping parameter name')
+        ax.plot(self.data['datetime'],
+                self.data[key][param],
+                label=self.data['names'].get(param, ''))
+    ax.set_xlabel('UTC')
+    ax.set_ylabel('Value')
+    return ax
+
+
+
+

Inherited members

+ +
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/index.html b/docs/stixdcpy/index.html new file mode 100644 index 0000000..e3cf0d5 --- /dev/null +++ b/docs/stixdcpy/index.html @@ -0,0 +1,144 @@ + + + + + + +stixdcpy API documentation + + + + + + + + + + + +
+
+
+

Package stixdcpy

+
+
+
+
+

Sub-modules

+
+
stixdcpy.ancillary
+
+

This module provides APIs to retrieve Quick-look data from STIX data center +,and some tools to display the data +Author: Hualin Xiao …

+
+
stixdcpy.cfl
+
+
+
+
stixdcpy.correction
+
+

This module provides algorithms to correct detector effects +Author: Hualin Xiao (hualin.xiao@fhnw.ch) +Date: Sep. 1, 2021

+
+
stixdcpy.detector_view
+
+
+
+
stixdcpy.energylut
+
+

This script provides APIs to retrieve energy +calibration data from STIX data center +,and some tools to display the data +Author: Hualin Xiao …

+
+
stixdcpy.housekeeping
+
+

This module provides APIs to retrieve Housekeeping data from STIX data center +,and some tools to display the data +Author: Hualin Xiao …

+
+
stixdcpy.instrument
+
+
+
+
stixdcpy.io
+
+
+
+
stixdcpy.logger
+
+
+
+
stixdcpy.net
+
+

This module provides APIs to retrieve data from STIX data center +Author: Hualin Xiao (hualin.xiao@fhnw.ch) +Date: Sep. 1, 2021

+
+
stixdcpy.quicklook
+
+

This module provides APIs to retrieve Quick-look data from STIX data center +,and some tools to display the data +Author: Hualin Xiao …

+
+
stixdcpy.science
+
+

This module provides APIs to retrieve Quick-look data from STIX data center , and provides tools to display the data +Author: Hualin Xiao …

+
+
stixdcpy.time
+
+
+
+
stixdcpy.transmission
+
+

calculation of stix transmission, taken from stixcore

+
+
stixdcpy.transmission_backup
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/instrument.html b/docs/stixdcpy/instrument.html new file mode 100644 index 0000000..a441751 --- /dev/null +++ b/docs/stixdcpy/instrument.html @@ -0,0 +1,1673 @@ + + + + + + +stixdcpy.instrument API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.instrument

+
+
+
+ +Expand source code + +
import math
+
+import numpy as np
+
+nominal_grid_parameters = {
+    "1": {
+        "Label": "3c",
+        "SlitWidth": 0.0419,
+        "FrontPitch": 0.078039,
+        "FrontOrient": 169.9559,
+        "RearPitch": 0.077364,
+        "RearOrient": 170.0437,
+        "PitchToler": 0.0000245,
+        "OrientToler": 0.0181,
+        "BridgePitch": 1.13,
+        "BridgeOrient": 80,
+        "BridgeWidth": 0.05
+    },
+    "2": {
+        "Label": "5c",
+        "SlitWidth": 0.0825,
+        "FrontPitch": 0.158078,
+        "FrontOrient": 130.3942,
+        "RearPitch": 0.159925,
+        "RearOrient": 129.6012,
+        "PitchToler": 0.000103,
+        "OrientToler": 0.037,
+        "BridgePitch": 1.97,
+        "BridgeOrient": 40,
+        "BridgeWidth": 0.05
+    },
+    "3": {
+        "Label": "10a",
+        "SlitWidth": 0.4793,
+        "FrontPitch": 0.909644,
+        "FrontOrient": 151.4808,
+        "RearPitch": 0.999045,
+        "RearOrient": 148.3736,
+        "PitchToler": 0.00368,
+        "OrientToler": 0.222,
+        "BridgePitch": "NA",
+        "BridgeOrient": "NA",
+        "BridgeWidth": "NA"
+    },
+    "4": {
+        "Label": "8c",
+        "SlitWidth": 0.2358,
+        "FrontPitch": 0.461187,
+        "FrontOrient": 68.589,
+        "RearPitch": 0.469602,
+        "RearOrient": 71.4367,
+        "PitchToler": 0.000879,
+        "OrientToler": 0.108,
+        "BridgePitch": 3.15,
+        "BridgeOrient": 160,
+        "BridgeWidth": 0.05
+    },
+    "5": {
+        "Label": "4b",
+        "SlitWidth": 0.0586,
+        "FrontPitch": 0.110594,
+        "FrontOrient": 29.82,
+        "RearPitch": 0.111811,
+        "RearOrient": 30.182,
+        "PitchToler": 0.0000502,
+        "OrientToler": 0.0259,
+        "BridgePitch": 1.69,
+        "BridgeOrient": 120,
+        "BridgeWidth": 0.05
+    },
+    "6": {
+        "Label": "5a",
+        "SlitWidth": 0.0825,
+        "FrontPitch": 0.158505,
+        "FrontOrient": 69.5151,
+        "RearPitch": 0.159487,
+        "RearOrient": 70.4879,
+        "PitchToler": 0.000103,
+        "OrientToler": 0.037,
+        "BridgePitch": 1.58,
+        "BridgeOrient": 160,
+        "BridgeWidth": 0.05
+    },
+    "7": {
+        "Label": "3a",
+        "SlitWidth": 0.0419,
+        "FrontPitch": 0.077582,
+        "FrontOrient": 110.2373,
+        "RearPitch": 0.077817,
+        "RearOrient": 109.7619,
+        "PitchToler": 0.0000245,
+        "OrientToler": 0.0181,
+        "BridgePitch": 1.05,
+        "BridgeOrient": 20,
+        "BridgeWidth": 0.05
+    },
+    "8": {
+        "Label": "7b",
+        "SlitWidth": 0.1657,
+        "FrontPitch": 0.320259,
+        "FrontOrient": 150.5213,
+        "RearPitch": 0.33068,
+        "RearOrient": 149.4617,
+        "PitchToler": 0.00043,
+        "OrientToler": 0.0757,
+        "BridgePitch": 2.66,
+        "BridgeOrient": 60,
+        "BridgeWidth": 0.05
+    },
+    "9": {
+        "Label": "CFL",
+        "SlitWidth": "NA",
+        "FrontPitch": "NA",
+        "FrontOrient": "NA",
+        "RearPitch": "NA",
+        "RearOrient": "NA",
+        "PitchToler": "NA",
+        "OrientToler": "NA",
+        "BridgePitch": "NA",
+        "BridgeOrient": "NA",
+        "BridgeWidth": "NA"
+    },
+    "10": {
+        "Label": "BKG",
+        "SlitWidth": "NA",
+        "FrontPitch": "NA",
+        "FrontOrient": "NA",
+        "RearPitch": "NA",
+        "RearOrient": "NA",
+        "PitchToler": "NA",
+        "OrientToler": "NA",
+        "BridgePitch": "NA",
+        "BridgeOrient": "NA",
+        "BridgeWidth": "NA"
+    },
+    "11": {
+        "Label": "1a",
+        "SlitWidth": 0.022,
+        "FrontPitch": 0.037929,
+        "FrontOrient": 150.0617,
+        "RearPitch": 0.038071,
+        "RearOrient": 149.938,
+        "PitchToler": 0.00000586,
+        "OrientToler": 0.00884,
+        "BridgePitch": 1.1,
+        "BridgeOrient": 60,
+        "BridgeWidth": 0.05
+    },
+    "12": {
+        "Label": "2a",
+        "SlitWidth": 0.0302,
+        "FrontPitch": 0.054408,
+        "FrontOrient": 129.8643,
+        "RearPitch": 0.054192,
+        "RearOrient": 130.1351,
+        "PitchToler": 0.000012,
+        "OrientToler": 0.0126,
+        "BridgePitch": 1.18,
+        "BridgeOrient": 40,
+        "BridgeWidth": 0.05
+    },
+    "13": {
+        "Label": "1b",
+        "SlitWidth": 0.022,
+        "FrontPitch": 0.038,
+        "FrontOrient": 90.1237,
+        "RearPitch": 0.038,
+        "RearOrient": 89.8763,
+        "PitchToler": 0.00000586,
+        "OrientToler": 0.00884,
+        "BridgePitch": 1.1,
+        "BridgeOrient": 0,
+        "BridgeWidth": 0.05
+    },
+    "14": {
+        "Label": "9b",
+        "SlitWidth": 0.336,
+        "FrontPitch": 0.674193,
+        "FrontOrient": 107.9371,
+        "RearPitch": 0.656988,
+        "RearOrient": 112.0102,
+        "PitchToler": 0.0018,
+        "OrientToler": 0.155,
+        "BridgePitch": "NA",
+        "BridgeOrient": "NA",
+        "BridgeWidth": "NA"
+    },
+    "15": {
+        "Label": "6a",
+        "SlitWidth": 0.1168,
+        "FrontPitch": 0.229395,
+        "FrontOrient": 50.5721,
+        "RearPitch": 0.225614,
+        "RearOrient": 49.4374,
+        "PitchToler": 0.00021,
+        "OrientToler": 0.0529,
+        "BridgePitch": 1.97,
+        "BridgeOrient": 140,
+        "BridgeWidth": 0.05
+    },
+    "16": {
+        "Label": "9a",
+        "SlitWidth": 0.336,
+        "FrontPitch": 0.641967,
+        "FrontOrient": 170.3629,
+        "RearPitch": 0.691656,
+        "RearOrient": 169.609,
+        "PitchToler": 0.0018,
+        "OrientToler": 0.155,
+        "BridgePitch": "NA",
+        "BridgeOrient": "NA",
+        "BridgeWidth": "NA"
+    },
+    "17": {
+        "Label": "2c",
+        "SlitWidth": 0.0302,
+        "FrontPitch": 0.054136,
+        "FrontOrient": 9.9694,
+        "RearPitch": 0.054465,
+        "RearOrient": 10.0308,
+        "PitchToler": 0.000012,
+        "OrientToler": 0.0126,
+        "BridgePitch": 1.13,
+        "BridgeOrient": 100,
+        "BridgeWidth": 0.05
+    },
+    "18": {
+        "Label": "1c",
+        "SlitWidth": 0.022,
+        "FrontPitch": 0.037929,
+        "FrontOrient": 29.9383,
+        "RearPitch": 0.038071,
+        "RearOrient": 30.062,
+        "PitchToler": 0.00000586,
+        "OrientToler": 0.00884,
+        "BridgePitch": 1.1,
+        "BridgeOrient": 120,
+        "BridgeWidth": 0.05
+    },
+    "19": {
+        "Label": "2b",
+        "SlitWidth": 0.0302,
+        "FrontPitch": 0.054357,
+        "FrontOrient": 70.1663,
+        "RearPitch": 0.054243,
+        "RearOrient": 69.8341,
+        "PitchToler": 0.000012,
+        "OrientToler": 0.0126,
+        "BridgePitch": 1.05,
+        "BridgeOrient": 160,
+        "BridgeWidth": 0.05
+    },
+    "20": {
+        "Label": "10b",
+        "SlitWidth": 0.4793,
+        "FrontPitch": 0.951208,
+        "FrontOrient": 86.9019,
+        "RearPitch": 0.951208,
+        "RearOrient": 93.0981,
+        "PitchToler": 0.00368,
+        "OrientToler": 0.222,
+        "BridgePitch": "NA",
+        "BridgeOrient": "NA",
+        "BridgeWidth": "NA"
+    },
+    "21": {
+        "Label": "8a",
+        "SlitWidth": 0.2358,
+        "FrontPitch": 0.453678,
+        "FrontOrient": 9.7435,
+        "RearPitch": 0.477944,
+        "RearOrient": 10.2702,
+        "PitchToler": 0.000879,
+        "OrientToler": 0.108,
+        "BridgePitch": 3.02,
+        "BridgeOrient": 100,
+        "BridgeWidth": 0.05
+    },
+    "22": {
+        "Label": "10c",
+        "SlitWidth": 0.4793,
+        "FrontPitch": 0.909644,
+        "FrontOrient": 28.5192,
+        "RearPitch": 0.999045,
+        "RearOrient": 31.6264,
+        "PitchToler": 0.00368,
+        "OrientToler": 0.222,
+        "BridgePitch": "NA",
+        "BridgeOrient": "NA",
+        "BridgeWidth": "NA"
+    },
+    "23": {
+        "Label": "4c",
+        "SlitWidth": 0.0586,
+        "FrontPitch": 0.110594,
+        "FrontOrient": 150.18,
+        "RearPitch": 0.111811,
+        "RearOrient": 149.818,
+        "PitchToler": 0.0000502,
+        "OrientToler": 0.0259,
+        "BridgePitch": 1.69,
+        "BridgeOrient": 60,
+        "BridgeWidth": 0.05
+    },
+    "24": {
+        "Label": "7a",
+        "SlitWidth": 0.1657,
+        "FrontPitch": 0.320259,
+        "FrontOrient": 29.4787,
+        "RearPitch": 0.33068,
+        "RearOrient": 30.5383,
+        "PitchToler": 0.00043,
+        "OrientToler": 0.0757,
+        "BridgePitch": 2.66,
+        "BridgeOrient": 120,
+        "BridgeWidth": 0.05
+    },
+    "25": {
+        "Label": "4a",
+        "SlitWidth": 0.0586,
+        "FrontPitch": 0.111198,
+        "FrontOrient": 89.638,
+        "RearPitch": 0.111198,
+        "RearOrient": 90.362,
+        "PitchToler": 0.0000502,
+        "OrientToler": 0.0259,
+        "BridgePitch": 1.1,
+        "BridgeOrient": 0,
+        "BridgeWidth": 0.05
+    },
+    "26": {
+        "Label": "8b",
+        "SlitWidth": 0.2358,
+        "FrontPitch": 0.457628,
+        "FrontOrient": 131.1413,
+        "RearPitch": 0.47345,
+        "RearOrient": 128.8192,
+        "PitchToler": 0.000879,
+        "OrientToler": 0.108,
+        "BridgePitch": 2.95,
+        "BridgeOrient": 40,
+        "BridgeWidth": 0.05
+    },
+    "27": {
+        "Label": "6b",
+        "SlitWidth": 0.1168,
+        "FrontPitch": 0.230433,
+        "FrontOrient": 169.8697,
+        "RearPitch": 0.22464,
+        "RearOrient": 170.127,
+        "PitchToler": 0.00021,
+        "OrientToler": 0.0529,
+        "BridgePitch": 2.28,
+        "BridgeOrient": 80,
+        "BridgeWidth": 0.05
+    },
+    "28": {
+        "Label": "7c",
+        "SlitWidth": 0.1657,
+        "FrontPitch": 0.325344,
+        "FrontOrient": 91.0592,
+        "RearPitch": 0.325344,
+        "RearOrient": 88.9408,
+        "PitchToler": 0.00043,
+        "OrientToler": 0.0757,
+        "BridgePitch": 2.2,
+        "BridgeOrient": 0,
+        "BridgeWidth": 0.05
+    },
+    "29": {
+        "Label": "3b",
+        "SlitWidth": 0.0419,
+        "FrontPitch": 0.077921,
+        "FrontOrient": 50.1943,
+        "RearPitch": 0.07748,
+        "RearOrient": 49.8068,
+        "PitchToler": 0.0000245,
+        "OrientToler": 0.0181,
+        "BridgePitch": 1.18,
+        "BridgeOrient": 140,
+        "BridgeWidth": 0.05
+    },
+    "30": {
+        "Label": "5b",
+        "SlitWidth": 0.0825,
+        "FrontPitch": 0.160427,
+        "FrontOrient": 10.0907,
+        "RearPitch": 0.157598,
+        "RearOrient": 9.9109,
+        "PitchToler": 0.000103,
+        "OrientToler": 0.037,
+        "BridgePitch": 1.81,
+        "BridgeOrient": 100,
+        "BridgeWidth": 0.05
+    },
+    "31": {
+        "Label": "6c",
+        "SlitWidth": 0.1168,
+        "FrontPitch": 0.228493,
+        "FrontOrient": 109.301,
+        "RearPitch": 0.226482,
+        "RearOrient": 110.6929,
+        "PitchToler": 0.00021,
+        "OrientToler": 0.0529,
+        "BridgePitch": 2.07,
+        "BridgeOrient": 20,
+        "BridgeWidth": 0.05
+    },
+    "32": {
+        "Label": "9c",
+        "SlitWidth": 0.336,
+        "FrontPitch": 0.682197,
+        "FrontOrient": 51.7015,
+        "RearPitch": 0.64983,
+        "RearOrient": 48.3792,
+        "PitchToler": 0.0018,
+        "OrientToler": 0.155,
+        "BridgePitch": "NA",
+        "BridgeOrient": "NA",
+        "BridgeWidth": "NA"
+    },
+    "33": {
+        "Label": "dummy",
+        "SlitWidth": 0.0302 * 0.5,
+        "FrontPitch": 0.054136 * 0.5,
+        "FrontOrient": 9.9694,
+        "RearPitch": 0.054465 * .5,
+        "RearOrient": 10.0308,
+        "PitchToler": 0.000012,
+        "OrientToler": 0.0126,
+        "BridgePitch": 1.13,
+        "BridgeOrient": 100,
+        "BridgeWidth": 0.05
+    },
+    '34': {
+        "Label": "9c",
+        "SlitWidth": 0.5,
+        "FrontPitch": 1,
+        "FrontOrient": 90,
+        "RearPitch": 1,
+        "RearOrient": 90,
+        "PitchToler": 0,
+        "OrientToler": 0,
+        "BridgePitch": "NA",
+        "BridgeOrient": "NA",
+        "BridgeWidth": "NA"
+    },
+    "units": {
+        "SlitWidth": "mm",
+        "FrontPitch": "mm",
+        "FrontOrient": "deg",
+        "RearPitch": "mm",
+        "RearOrient": "deg",
+        "PitchToler": "mm",
+        "OrientToler": "deg",
+        "BridgePitch": "mm",
+        "BridgeOrient": "deg",
+        "BridgeWidth": "mm",
+        "AvgOrient": 'deg',
+        'AngRes': 'arcsec',
+        'Pitch': 'mm',
+    },
+}
+# data from matj
+real_grid_parameters = {
+    "1": {
+        "FrontPitch": 0.07805,
+        "FrontOrient": 169.977,
+        "FrontPhase": 0.0048,
+        "FrontSlitWidth": 0.0457,
+        "FrontSlitGradient": 0.0009,
+        "FrontRMS": 0.0012,
+        "FrontThickness": 0.3538,
+        "FrontBridgeWidth": 0.0433,
+        "FrontBridgePitch": 1.130299,
+        "RearPitch": 0.077388,
+        "RearOrient": 170.037,
+        "RearPhase": 0.0173,
+        "RearSlitWidth": 0.0507,
+        "RearSlitGradient": 0.0007,
+        "RearRMS": 0.0011,
+        "RearThickness": 0.3628,
+        "RearBridgeWidth": 0.0398,
+        "RearBridgePitch": 1.130199
+    },
+    "2": {
+        "FrontPitch": 0.158102,
+        "FrontOrient": 130.406,
+        "FrontPhase": 0.1136,
+        "FrontSlitWidth": 0.07645,
+        "FrontSlitGradient": 0.0008,
+        "FrontRMS": 0.0009,
+        "FrontThickness": 0.3897,
+        "FrontBridgeWidth": 0.0587,
+        "FrontBridgePitch": 1.970416,
+        "RearPitch": 0.159965,
+        "RearOrient": 129.588,
+        "RearPhase": 0.1497,
+        "RearSlitWidth": 0.0806,
+        "RearSlitGradient": 0.0004,
+        "RearRMS": 0.0008,
+        "RearThickness": 0.3901,
+        "RearBridgeWidth": 0.0543,
+        "RearBridgePitch": 1.970729
+    },
+    "3": {
+        "FrontPitch": 0.909818,
+        "FrontOrient": 151.503,
+        "FrontPhase": 0.1114,
+        "FrontSlitWidth": 0.4811,
+        "FrontSlitGradient": 0.0008,
+        "FrontRMS": 0.0014,
+        "FrontThickness": 0.4413,
+        "FrontBridgeWidth": 0,
+        "FrontBridgePitch": 0,
+        "RearPitch": 0.999226,
+        "RearOrient": 148.373,
+        "RearPhase": 0.086,
+        "RearSlitWidth": 0.492,
+        "RearSlitGradient": 0.0026,
+        "RearRMS": 0.0011,
+        "RearThickness": 0.421,
+        "RearBridgeWidth": 0,
+        "RearBridgePitch": 0
+    },
+    "4": {
+        "FrontPitch": 0.46131,
+        "FrontOrient": 68.608,
+        "FrontPhase": 0.1562,
+        "FrontSlitWidth": 0.2352,
+        "FrontSlitGradient": 0.0004,
+        "FrontRMS": 0.0011,
+        "FrontThickness": 0.4171,
+        "FrontBridgeWidth": 0.0426,
+        "FrontBridgePitch": 3.150334,
+        "RearPitch": 0.469697,
+        "RearOrient": 71.434,
+        "RearPhase": 0.456,
+        "RearSlitWidth": 0.2431,
+        "RearSlitGradient": 0.0029,
+        "RearRMS": 0.001,
+        "RearThickness": 0.3922,
+        "RearBridgeWidth": 0.0416,
+        "RearBridgePitch": 3.150274
+    },
+    "5": {
+        "FrontPitch": 0.110609,
+        "FrontOrient": 29.839,
+        "FrontPhase": 0.0102,
+        "FrontSlitWidth": 0.0566,
+        "FrontSlitGradient": 0.0009,
+        "FrontRMS": 0.0008,
+        "FrontThickness": 0.3813,
+        "FrontBridgeWidth": 0.5,
+        "FrontBridgePitch": 1.65,
+        "RearPitch": 0.111831,
+        "RearOrient": 30.18,
+        "RearPhase": 0.0497,
+        "RearSlitWidth": 0.0623,
+        "RearSlitGradient": 0.0005,
+        "RearRMS": 0.0009,
+        "RearThickness": 0.4082,
+        "RearBridgeWidth": 0.0378,
+        "RearBridgePitch": 1.690653
+    },
+    "6": {
+        "FrontPitch": 0.15853,
+        "FrontOrient": 69.527,
+        "FrontPhase": 0.0247,
+        "FrontSlitWidth": 0.0741,
+        "FrontSlitGradient": 0.0007,
+        "FrontRMS": 0.0007,
+        "FrontThickness": 0.3924,
+        "FrontBridgeWidth": 0.0618,
+        "FrontBridgePitch": 1.580188,
+        "RearPitch": 0.159539,
+        "RearOrient": 70.48,
+        "RearPhase": 0.0086,
+        "RearSlitWidth": 0.0849,
+        "RearSlitGradient": 0.0006,
+        "RearRMS": 0.0007,
+        "RearThickness": 0.4226,
+        "RearBridgeWidth": 0.0582,
+        "RearBridgePitch": 1.580039
+    },
+    "7": {
+        "FrontPitch": 0.077594,
+        "FrontOrient": 110.252,
+        "FrontPhase": 0.0195,
+        "FrontSlitWidth": 0.0465,
+        "FrontSlitGradient": 0.0019,
+        "FrontRMS": 0.0009,
+        "FrontThickness": 0.374,
+        "FrontBridgeWidth": 0.0422,
+        "FrontBridgePitch": 1.050062,
+        "RearPitch": 0.077834,
+        "RearOrient": 109.754,
+        "RearPhase": 0.0388,
+        "RearSlitWidth": 0.0534,
+        "RearSlitGradient": 0.0012,
+        "RearRMS": 0.0007,
+        "RearThickness": 0.3896,
+        "RearBridgeWidth": 0.0399,
+        "RearBridgePitch": 1.050446
+    },
+    "8": {
+        "FrontPitch": 0.32033,
+        "FrontOrient": 150.541,
+        "FrontPhase": 0.0178,
+        "FrontSlitWidth": 0.1589,
+        "FrontSlitGradient": 0.0006,
+        "FrontRMS": 0.0008,
+        "FrontThickness": 0.405,
+        "FrontBridgeWidth": 0.0441,
+        "FrontBridgePitch": 2.661093,
+        "RearPitch": 0.330751,
+        "RearOrient": 149.46,
+        "RearPhase": 0.3021,
+        "RearSlitWidth": 0.1712,
+        "RearSlitGradient": 0.001,
+        "RearRMS": 0.0009,
+        "RearThickness": 0.3805,
+        "RearBridgeWidth": 0.0434,
+        "RearBridgePitch": 2.660393
+    },
+    "9": {
+        "FrontPitch": "CFL",
+        "FrontOrient": "CFL",
+        "FrontPhase": "CFL",
+        "FrontSlitWidth": "CFL",
+        "FrontSlitGradient": "CFL",
+        "FrontRMS": "CFL",
+        "FrontThickness": "CFL",
+        "FrontBridgeWidth": "CFL",
+        "FrontBridgePitch": "CFL",
+        "RearPitch": "CFL",
+        "RearOrient": "CFL",
+        "RearPhase": "CFL",
+        "RearSlitWidth": "CFL",
+        "RearSlitGradient": "CFL",
+        "RearRMS": "CFL",
+        "RearThickness": "CFL",
+        "RearBridgeWidth": "CFL",
+        "RearBridgePitch": "CFL"
+    },
+    "10": {
+        "FrontPitch": "BKG",
+        "FrontOrient": "BKG",
+        "FrontPhase": "BKG",
+        "FrontSlitWidth": "BKG",
+        "FrontSlitGradient": "BKG",
+        "FrontRMS": "BKG",
+        "FrontThickness": "BKG",
+        "FrontBridgeWidth": "BKG",
+        "FrontBridgePitch": "BKG",
+        "RearPitch": "BKG",
+        "RearOrient": "BKG",
+        "RearPhase": "BKG",
+        "RearSlitWidth": "BKG",
+        "RearSlitGradient": "BKG",
+        "RearRMS": "BKG",
+        "RearThickness": "BKG",
+        "RearBridgeWidth": "BKG",
+        "RearBridgePitch": "BKG"
+    },
+    "11": {
+        "FrontPitch": 0.113799,
+        "FrontOrient": 150.076,
+        "FrontPhase": 0.0147,
+        "FrontSlitWidth": 0.0934,
+        "FrontSlitGradient": 0.0013,
+        "FrontRMS": 0.0011,
+        "FrontThickness": "Non-recov.",
+        "FrontBridgeWidth": 0.0464,
+        "FrontBridgePitch": 1.099888,
+        "RearPitch": 0.114224,
+        "RearOrient": 149.93,
+        "RearPhase": 0.0668,
+        "RearSlitWidth": 0.0971,
+        "RearSlitGradient": 0.0004,
+        "RearRMS": 0.0011,
+        "RearThickness": "Non-recov.",
+        "RearBridgeWidth": 0.0495,
+        "RearBridgePitch": 1.100279
+    },
+    "15": {
+        "FrontPitch": 0.229421,
+        "FrontOrient": 50.582,
+        "FrontPhase": 0.0469,
+        "FrontSlitWidth": 0.1094,
+        "FrontSlitGradient": 0.0014,
+        "FrontRMS": 0.0016,
+        "FrontThickness": 0.3819,
+        "FrontBridgeWidth": 0.0516,
+        "FrontBridgePitch": 1.970634,
+        "RearPitch": 0.225653,
+        "RearOrient": 49.427,
+        "RearPhase": 0.0326,
+        "RearSlitWidth": 0.1155,
+        "RearSlitGradient": 0.002,
+        "RearRMS": 0.0014,
+        "RearThickness": 0.3787,
+        "RearBridgeWidth": 0.0527,
+        "RearBridgePitch": 1.970511
+    },
+    "16": {
+        "FrontPitch": 0.642102,
+        "FrontOrient": 170.393,
+        "FrontPhase": 0.0152,
+        "FrontSlitWidth": 0.3364,
+        "FrontSlitGradient": 0.0031,
+        "FrontRMS": 0.0014,
+        "FrontThickness": 0.4011,
+        "FrontBridgeWidth": 0,
+        "FrontBridgePitch": 0,
+        "RearPitch": 0.691758,
+        "RearOrient": 169.609,
+        "RearPhase": 0.3612,
+        "RearSlitWidth": 0.3451,
+        "RearSlitGradient": 0.0021,
+        "RearRMS": 0.0011,
+        "RearThickness": 0.4053,
+        "RearBridgeWidth": 0,
+        "RearBridgePitch": 0
+    },
+    "20": {
+        "FrontPitch": 0.951346,
+        "FrontOrient": 86.916,
+        "FrontPhase": 0.913,
+        "FrontSlitWidth": 0.4903,
+        "FrontSlitGradient": 0.0017,
+        "FrontRMS": 0.0012,
+        "FrontThickness": 0.4375,
+        "FrontBridgeWidth": 0,
+        "FrontBridgePitch": 0,
+        "RearPitch": 0.951412,
+        "RearOrient": 93.105,
+        "RearPhase": 0.2194,
+        "RearSlitWidth": 0.492,
+        "RearSlitGradient": 0.0039,
+        "RearRMS": 0.0014,
+        "RearThickness": 0.4052,
+        "RearBridgeWidth": 0,
+        "RearBridgePitch": 0
+    },
+    "21": {
+        "FrontPitch": 0.453733,
+        "FrontOrient": 9.763,
+        "FrontPhase": 0.1752,
+        "FrontSlitWidth": 0.2286,
+        "FrontSlitGradient": 0.0024,
+        "FrontRMS": 0.0019,
+        "FrontThickness": 0.3819,
+        "FrontBridgeWidth": 0.0463,
+        "FrontBridgePitch": 3.020667,
+        "RearPitch": 0.478018,
+        "RearOrient": 10.273,
+        "RearPhase": 0.4254,
+        "RearSlitWidth": 0.2415,
+        "RearSlitGradient": 0.0012,
+        "RearRMS": 0.0014,
+        "RearThickness": 0.3866,
+        "RearBridgeWidth": 0.0436,
+        "RearBridgePitch": 3.021032
+    },
+    "22": {
+        "FrontPitch": 0.909875,
+        "FrontOrient": 28.534,
+        "FrontPhase": 0.7453,
+        "FrontSlitWidth": 0.4781,
+        "FrontSlitGradient": 0.0009,
+        "FrontRMS": 0.0027,
+        "FrontThickness": 0.4153,
+        "FrontBridgeWidth": 0,
+        "FrontBridgePitch": 0,
+        "RearPitch": 0.999212,
+        "RearOrient": 31.621,
+        "RearPhase": 0.2162,
+        "RearSlitWidth": 0.4878,
+        "RearSlitGradient": 0.0026,
+        "RearRMS": 0.0016,
+        "RearThickness": 0.4144,
+        "RearBridgeWidth": 0,
+        "RearBridgePitch": 0
+    },
+    "23": {
+        "FrontPitch": 0.110621,
+        "FrontOrient": 150.188,
+        "FrontPhase": 0.0762,
+        "FrontSlitWidth": 0.0555,
+        "FrontSlitGradient": 0.001,
+        "FrontRMS": 0.0009,
+        "FrontThickness": 0.3714,
+        "FrontBridgeWidth": 0.0356,
+        "FrontBridgePitch": 1.690305,
+        "RearPitch": 0.111829,
+        "RearOrient": 149.804,
+        "RearPhase": 0.038,
+        "RearSlitWidth": 0.0624,
+        "RearSlitGradient": 0.0009,
+        "RearRMS": 0.0009,
+        "RearThickness": 0.3947,
+        "RearBridgeWidth": 0.0391,
+        "RearBridgePitch": 1.69002
+    },
+    "24": {
+        "FrontPitch": 0.320329,
+        "FrontOrient": 29.494,
+        "FrontPhase": 0.192,
+        "FrontSlitWidth": 0.1555,
+        "FrontSlitGradient": 0.001,
+        "FrontRMS": 0.0011,
+        "FrontThickness": 0.4183,
+        "FrontBridgeWidth": 0.0508,
+        "FrontBridgePitch": 2.660021,
+        "RearPitch": 0.330741,
+        "RearOrient": 30.534,
+        "RearPhase": 0.2552,
+        "RearSlitWidth": 0.1632,
+        "RearSlitGradient": 0.0005,
+        "RearRMS": 0.001,
+        "RearThickness": 0.4123,
+        "RearBridgeWidth": 0.0467,
+        "RearBridgePitch": 2.660331
+    },
+    "25": {
+        "FrontPitch": 0.111218,
+        "FrontOrient": 89.65,
+        "FrontPhase": 0.0078,
+        "FrontSlitWidth": 0.0575,
+        "FrontSlitGradient": 0.0009,
+        "FrontRMS": 0.0006,
+        "FrontThickness": 0.391,
+        "FrontBridgeWidth": 0.0386,
+        "FrontBridgePitch": 1.100597,
+        "RearPitch": 0.111216,
+        "RearOrient": 90.354,
+        "RearPhase": 0.1018,
+        "RearSlitWidth": 0.0626,
+        "RearSlitGradient": 0.0008,
+        "RearRMS": 0.0005,
+        "RearThickness": 0.3697,
+        "RearBridgeWidth": 0.042,
+        "RearBridgePitch": 1.09966
+    },
+    "26": {
+        "FrontPitch": 0.457701,
+        "FrontOrient": 131.16,
+        "FrontPhase": 0.1632,
+        "FrontSlitWidth": 0.2307,
+        "FrontSlitGradient": 0.0044,
+        "FrontRMS": 0.0014,
+        "FrontThickness": 0.3609,
+        "FrontBridgeWidth": 0.0492,
+        "FrontBridgePitch": 2.9513,
+        "RearPitch": 0.473501,
+        "RearOrient": 128.82,
+        "RearPhase": 0.3551,
+        "RearSlitWidth": 0.241,
+        "RearSlitGradient": 0.0057,
+        "RearRMS": 0.0015,
+        "RearThickness": 0.3879,
+        "RearBridgeWidth": 0.0399,
+        "RearBridgePitch": 2.949872
+    },
+    "27": {
+        "FrontPitch": 0.23049,
+        "FrontOrient": 169.887,
+        "FrontPhase": 0.0272,
+        "FrontSlitWidth": 0.1039,
+        "FrontSlitGradient": 0.0017,
+        "FrontRMS": 0.0016,
+        "FrontThickness": 0.3476,
+        "FrontBridgeWidth": 0.0568,
+        "FrontBridgePitch": 2.280569,
+        "RearPitch": 0.224674,
+        "RearOrient": 170.124,
+        "RearPhase": 0.2222,
+        "RearSlitWidth": 0.1155,
+        "RearSlitGradient": 0.0024,
+        "RearRMS": 0.0011,
+        "RearThickness": 0.3676,
+        "RearBridgeWidth": 0.0567,
+        "RearBridgePitch": 2.279257
+    },
+    "28": {
+        "FrontPitch": 0.32543,
+        "FrontOrient": 91.078,
+        "FrontPhase": 0.2984,
+        "FrontSlitWidth": 0.1679,
+        "FrontSlitGradient": 0.0006,
+        "FrontRMS": 0.0013,
+        "FrontThickness": 0.4149,
+        "FrontBridgeWidth": 0.0554,
+        "FrontBridgePitch": 2.200088,
+        "RearPitch": 0.325412,
+        "RearOrient": 88.938,
+        "RearPhase": 0.058,
+        "RearSlitWidth": 0.171,
+        "RearSlitGradient": 0.0014,
+        "RearRMS": 0.0015,
+        "RearThickness": 0.3852,
+        "RearBridgeWidth": 0.0521,
+        "RearBridgePitch": 2.200617
+    },
+    "29": {
+        "FrontPitch": 0.077934,
+        "FrontOrient": 50.203,
+        "FrontPhase": 0.0628,
+        "FrontSlitWidth": 0.046,
+        "FrontSlitGradient": 0.0011,
+        "FrontRMS": 0.0009,
+        "FrontThickness": 0.3597,
+        "FrontBridgeWidth": 0.0446,
+        "FrontBridgePitch": 1.180051,
+        "RearPitch": 0.077494,
+        "RearOrient": 49.798,
+        "RearPhase": 0.0494,
+        "RearSlitWidth": 0.0513,
+        "RearSlitGradient": 0.0005,
+        "RearRMS": 0.0007,
+        "RearThickness": 0.3546,
+        "RearBridgeWidth": 0.0357,
+        "RearBridgePitch": 1.180175
+    },
+    "30": {
+        "FrontPitch": 0.16043,
+        "FrontOrient": 10.117,
+        "FrontPhase": 0.0749,
+        "FrontSlitWidth": 0.0772,
+        "FrontSlitGradient": 0.0007,
+        "FrontRMS": 0.0011,
+        "FrontThickness": 0.3903,
+        "FrontBridgeWidth": 0.059,
+        "FrontBridgePitch": 1.810433,
+        "RearPitch": 0.157633,
+        "RearOrient": 9.911,
+        "RearPhase": 0.0927,
+        "RearSlitWidth": 0.0852,
+        "RearSlitGradient": 0.0008,
+        "RearRMS": 0.001,
+        "RearThickness": 0.3989,
+        "RearBridgeWidth": 0.0615,
+        "RearBridgePitch": 1.810039
+    },
+    "31": {
+        "FrontPitch": 0.228531,
+        "FrontOrient": 109.323,
+        "FrontPhase": 0.0969,
+        "FrontSlitWidth": 0.119,
+        "FrontSlitGradient": 0.0006,
+        "FrontRMS": 0.001,
+        "FrontThickness": 0.3838,
+        "FrontBridgeWidth": 0.0595,
+        "FrontBridgePitch": 2.070182,
+        "RearPitch": 0.226511,
+        "RearOrient": 110.694,
+        "RearPhase": 0.1825,
+        "RearSlitWidth": 0.115,
+        "RearSlitGradient": 0.001,
+        "RearRMS": 0.0013,
+        "RearThickness": 0.365,
+        "RearBridgeWidth": 0.0541,
+        "RearBridgePitch": 2.070283
+    },
+    "32": {
+        "FrontPitch": 0.682253,
+        "FrontOrient": 51.714,
+        "FrontPhase": 0.4855,
+        "FrontSlitWidth": 0.3384,
+        "FrontSlitGradient": 0.0018,
+        "FrontRMS": 0.0032,
+        "FrontThickness": 0.398,
+        "FrontBridgeWidth": 0,
+        "FrontBridgePitch": 0,
+        "RearPitch": 0.649947,
+        "RearOrient": 48.378,
+        "RearPhase": 0.3333,
+        "RearSlitWidth": 0.3421,
+        "RearSlitGradient": 0.0034,
+        "RearRMS": 0.0012,
+        "RearThickness": 0.3884,
+        "RearBridgeWidth": 0,
+        "RearBridgePitch": 0
+    },
+    "12a": {
+        "FrontPitch": 0.108817,
+        "FrontOrient": 129.883,
+        "FrontPhase": 0.059,
+        "FrontSlitWidth": 0.0795,
+        "FrontSlitGradient": 0.0014,
+        "FrontRMS": 0.001,
+        "FrontThickness": "Non-recov.",
+        "FrontBridgeWidth": 0.044,
+        "FrontBridgePitch": 1.180036,
+        "RearPitch": 0.108394,
+        "RearOrient": 130.131,
+        "RearPhase": 0.0542,
+        "RearSlitWidth": 0.0813,
+        "RearSlitGradient": 0.0003,
+        "RearRMS": 0.001,
+        "RearThickness": "Non-recov.",
+        "RearBridgeWidth": 0.0462,
+        "RearBridgePitch": 1.180239
+    },
+    "12b": {
+        "FrontPitch": 0.108825,
+        "FrontOrient": 129.879,
+        "FrontPhase": 0.0032,
+        "FrontSlitWidth": 0.0835,
+        "FrontSlitGradient": 0.0008,
+        "FrontRMS": 0.001,
+        "FrontThickness": "Non-recov.",
+        "FrontBridgeWidth": "",
+        "FrontBridgePitch": "",
+        "RearPitch": 0.108406,
+        "RearOrient": 130.131,
+        "RearPhase": 0.1026,
+        "RearSlitWidth": 0.081,
+        "RearSlitGradient": 0.0005,
+        "RearRMS": 0.001,
+        "RearThickness": "Non-recov.",
+        "RearBridgeWidth": "",
+        "RearBridgePitch": ""
+    },
+    "13a": {
+        "FrontPitch": 0.113998,
+        "FrontOrient": 90.143,
+        "FrontPhase": 0.0533,
+        "FrontSlitWidth": 0.0919,
+        "FrontSlitGradient": 0.0019,
+        "FrontRMS": 0.0009,
+        "FrontThickness": "Non-recov.",
+        "FrontBridgeWidth": "",
+        "FrontBridgePitch": "",
+        "RearPitch": 0.113995,
+        "RearOrient": 89.865,
+        "RearPhase": 0.0362,
+        "RearSlitWidth": 0.0915,
+        "RearSlitGradient": 0.0007,
+        "RearRMS": 0.0008,
+        "RearThickness": "Non-recov.",
+        "RearBridgeWidth": "",
+        "RearBridgePitch": ""
+    },
+    "13b": {
+        "FrontPitch": 0.114008,
+        "FrontOrient": 90.137,
+        "FrontPhase": 0.0121,
+        "FrontSlitWidth": 0.0867,
+        "FrontSlitGradient": 0.0008,
+        "FrontRMS": 0.0008,
+        "FrontThickness": "Non-recov.",
+        "FrontBridgeWidth": "",
+        "FrontBridgePitch": "",
+        "RearPitch": 0.114015,
+        "RearOrient": 89.862,
+        "RearPhase": 0.0658,
+        "RearSlitWidth": 0.0833,
+        "RearSlitGradient": 0.0009,
+        "RearRMS": 0.0009,
+        "RearThickness": "Non-recov.",
+        "RearBridgeWidth": "",
+        "RearBridgePitch": ""
+    },
+    "14c": {
+        "FrontPitch": 0.674276,
+        "FrontOrient": 107.955,
+        "FrontPhase": 0.0477,
+        "FrontSlitWidth": 0.3377,
+        "FrontSlitGradient": 0.0006,
+        "FrontRMS": 0.0016,
+        "FrontThickness": 0.4024,
+        "FrontBridgeWidth": 0,
+        "FrontBridgePitch": 0,
+        "RearPitch": 0.657124,
+        "RearOrient": 112.013,
+        "RearPhase": 0.2675,
+        "RearSlitWidth": 0.3455,
+        "RearSlitGradient": 0.0031,
+        "RearRMS": 0.0013,
+        "RearThickness": 0.3977,
+        "RearBridgeWidth": 0,
+        "RearBridgePitch": 0
+    },
+    "17a": {
+        "FrontPitch": 0.108278,
+        "FrontOrient": 9.995,
+        "FrontPhase": 0.1656,
+        "FrontSlitWidth": 0.0839,
+        "FrontSlitGradient": 0.0007,
+        "FrontRMS": 0.0012,
+        "FrontThickness": "Non-recov.",
+        "FrontBridgeWidth": 0.0544,
+        "FrontBridgePitch": 1.130375,
+        "RearPitch": 0.10894,
+        "RearOrient": 10.031,
+        "RearPhase": 0.1056,
+        "RearSlitWidth": 0.0861,
+        "RearSlitGradient": 0.0004,
+        "RearRMS": 0.001,
+        "RearThickness": "Non-recov.",
+        "RearBridgeWidth": 0.0594,
+        "RearBridgePitch": 1.129875
+    },
+    "17b": {
+        "FrontPitch": 0.108286,
+        "FrontOrient": 9.99,
+        "FrontPhase": 0.0569,
+        "FrontSlitWidth": 0.0852,
+        "FrontSlitGradient": 0.0008,
+        "FrontRMS": 0.0011,
+        "FrontThickness": "Non-recov.",
+        "FrontBridgeWidth": "",
+        "FrontBridgePitch": "",
+        "RearPitch": 0.108958,
+        "RearOrient": 10.034,
+        "RearPhase": 0.0523,
+        "RearSlitWidth": 0.0845,
+        "RearSlitGradient": 0.0005,
+        "RearRMS": 0.0009,
+        "RearThickness": "Non-recov.",
+        "RearBridgeWidth": "",
+        "RearBridgePitch": ""
+    },
+    "18a": {
+        "FrontPitch": 0.113806,
+        "FrontOrient": 29.957,
+        "FrontPhase": 0.0366,
+        "FrontSlitWidth": 0.0881,
+        "FrontSlitGradient": 0.002,
+        "FrontRMS": 0.0013,
+        "FrontThickness": "Non-recov.",
+        "FrontBridgeWidth": 0.0469,
+        "FrontBridgePitch": 1.100317,
+        "RearPitch": 0.114231,
+        "RearOrient": 30.058,
+        "RearPhase": 0.0923,
+        "RearSlitWidth": 0.0954,
+        "RearSlitGradient": 0.0007,
+        "RearRMS": 0.0013,
+        "RearThickness": "Non-recov.",
+        "RearBridgeWidth": 0.0506,
+        "RearBridgePitch": 1.100059
+    },
+    "18b": {
+        "FrontPitch": 0.113801,
+        "FrontOrient": 29.954,
+        "FrontPhase": 0.106,
+        "FrontSlitWidth": 0.0929,
+        "FrontSlitGradient": 0.0007,
+        "FrontRMS": 0.0011,
+        "FrontThickness": "Non-recov.",
+        "FrontBridgeWidth": "",
+        "FrontBridgePitch": "",
+        "RearPitch": 0.11422,
+        "RearOrient": 30.063,
+        "RearPhase": 0.0608,
+        "RearSlitWidth": 0.0941,
+        "RearSlitGradient": 0.0006,
+        "RearRMS": 0.0011,
+        "RearThickness": "Non-recov.",
+        "RearBridgeWidth": "",
+        "RearBridgePitch": ""
+    },
+    "18c": {
+        "FrontPitch": 0.113808,
+        "FrontOrient": 29.956,
+        "FrontPhase": 0.071,
+        "FrontSlitWidth": 0.0929,
+        "FrontSlitGradient": 0.0011,
+        "FrontRMS": 0.0011,
+        "FrontThickness": "Non-recov.",
+        "FrontBridgeWidth": "",
+        "FrontBridgePitch": "",
+        "RearPitch": 0.114238,
+        "RearOrient": 30.06,
+        "RearPhase": 0.0166,
+        "RearSlitWidth": 0.0919,
+        "RearSlitGradient": 0.0014,
+        "RearRMS": 0.0011,
+        "RearThickness": "Non-recov.",
+        "RearBridgeWidth": "",
+        "RearBridgePitch": ""
+    },
+    "19a": {
+        "FrontPitch": 0.108729,
+        "FrontOrient": 70.188,
+        "FrontPhase": 0.0098,
+        "FrontSlitWidth": 0.0833,
+        "FrontSlitGradient": 0.0012,
+        "FrontRMS": 0.0007,
+        "FrontThickness": "Non-recov.",
+        "FrontBridgeWidth": "",
+        "FrontBridgePitch": "",
+        "RearPitch": 0.108493,
+        "RearOrient": 69.834,
+        "RearPhase": 0.0257,
+        "RearSlitWidth": 0.0814,
+        "RearSlitGradient": 0.0009,
+        "RearRMS": 0.0009,
+        "RearThickness": "Non-recov.",
+        "RearBridgeWidth": "",
+        "RearBridgePitch": ""
+    }
+}
+detector_center_coords = {
+    "1": {
+        "x": -62.5,
+        "y": 36.5
+    },
+    "2": {
+        "x": -62.5,
+        "y": 13.5
+    },
+    "3": {
+        "x": -62.5,
+        "y": -13.5
+    },
+    "4": {
+        "x": -62.5,
+        "y": -36.5
+    },
+    "5": {
+        "x": -37.5,
+        "y": 59.5
+    },
+    "6": {
+        "x": -37.5,
+        "y": 36.5
+    },
+    "7": {
+        "x": -37.5,
+        "y": 13.5
+    },
+    "8": {
+        "x": -37.5,
+        "y": -13.5
+    },
+    "9": {
+        "x": -37.5,
+        "y": -36.5
+    },
+    "10": {
+        "x": -37.5,
+        "y": -59.5
+    },
+    "11": {
+        "x": -12.5,
+        "y": 73.5
+    },
+    "12": {
+        "x": -12.5,
+        "y": 50.5
+    },
+    "13": {
+        "x": -12.5,
+        "y": 27.5
+    },
+    "14": {
+        "x": -12.5,
+        "y": -27.5
+    },
+    "15": {
+        "x": -12.5,
+        "y": -50.5
+    },
+    "16": {
+        "x": -12.5,
+        "y": -73.5
+    },
+    "17": {
+        "x": 12.5,
+        "y": 73.5
+    },
+    "18": {
+        "x": 12.5,
+        "y": 50.5
+    },
+    "19": {
+        "x": 12.5,
+        "y": 27.5
+    },
+    "20": {
+        "x": 12.5,
+        "y": -27.5
+    },
+    "21": {
+        "x": 12.5,
+        "y": -50.5
+    },
+    "22": {
+        "x": 12.5,
+        "y": -73.5
+    },
+    "23": {
+        "x": 37.5,
+        "y": 59.5
+    },
+    "24": {
+        "x": 37.5,
+        "y": 36.5
+    },
+    "25": {
+        "x": 37.5,
+        "y": 13.5
+    },
+    "26": {
+        "x": 37.5,
+        "y": -13.5
+    },
+    "27": {
+        "x": 37.5,
+        "y": -36.5
+    },
+    "28": {
+        "x": 37.5,
+        "y": -59.5
+    },
+    "29": {
+        "x": 62.5,
+        "y": 36.5
+    },
+    "30": {
+        "x": 62.5,
+        "y": 13.5
+    },
+    "31": {
+        "x": 62.5,
+        "y": -13.5
+    },
+    "32": {
+        "x": 62.5,
+        "y": -36.5
+    }
+}
+cfl_hole_coords = {
+    'outer': [(-14.3, -13.45), (-14.3, 13.45), (14.3, 13.45), (14.3, -13.45)],
+    'top': [(-4.4, 3.45), (-4.4, 10.0), (4.4, 10.0), (4.4, 3.45)],
+    'bottom': [(-4.4, -10.0), (-4.4, -3.45), (4.4, -3.45), (4.4, -10.0)],
+    'left_top': [(-11.0, 3.45), (-11.0, 10.0), (-9.9, 10.0), (-9.9, 3.45)],
+    'left_bottom': [(-11.0, -10.0), (-11.0, -3.45), (-9.9, -3.45),
+                    (-9.9, -10.0)],
+    'right_top': [(9.9, 3.45), (9.9, 10.0), (11.0, 10.0), (11.0, 3.45)],
+    'right_bottom': [(9.9, -10.0), (9.9, -3.45), (11.0, -3.45), (11.0, -10.0)]
+}
+
+r_front_detector = 550 + 47  # measured from CAD
+r_rear_detector = 47
+frame_vertices = {
+    'front': [(-11, -10), (-11, 10), (11, 10), (11, -10), (-11, -10)],
+    'rear': [(-6.5, -6.5), (-6.5, 6.5), (6.5, 6.5), (6.5, -6.5), (-6.5, -6.5)]
+}
+grid_dim = {'front': (22, 20), 'rear': (13, 13)}  # grid dimemsions
+grid_z = {
+    'det': 0,
+    'rear': r_rear_detector,
+    'front': r_front_detector
+}  # grid z coordinates
+
+bkg_hole_coords = {}
+
+ebin_low_edges = np.array([
+    0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 25, 28, 32,
+    36, 40, 45, 50, 56, 63, 70, 76, 84, 100, 120, 150, math.inf
+])
+ebins = np.vstack((ebin_low_edges[0:-1], ebin_low_edges[1:])).T
+detector_ids_in_trigger_accumulators = np.array([[1, 2], [6, 7], [5, 11], [12, 13], [14, 15],
+                                                [10, 16], [8, 9], [3, 4], [
+                                                    31, 32], [26, 27],
+                                                 [22, 28], [20, 21], [18, 19], [
+                                                     17, 23], [24, 25],
+                                                 [29, 30]])-1
+# detector ids of in trigger accounumator
+detector_group_map = np.array([
+    0, 0, 7, 7, 2, 1, 1, 6, 6, 5, 2, 3, 3, 4, 4, 5, 13, 12, 12, 11, 11, 10, 13,
+    14, 14, 9, 9, 10, 15, 15, 8, 8
+])
+
+detector_pairs = {
+    0: 1,
+    5: 6,
+    4: 10,
+    11: 12,
+    13: 14,
+    9: 15,
+    7: 8,
+    2: 3,
+    30: 31,
+    25: 26,
+    21: 27,
+    19: 20,
+    17: 18,
+    16: 22,
+    23: 24,
+    28: 29,
+    1: 0,
+    6: 5,
+    10: 4,
+    12: 11,
+    14: 13,
+    15: 9,
+    8: 7,
+    3: 2,
+    31: 30,
+    26: 25,
+    27: 21,
+    20: 19,
+    18: 17,
+    22: 16,
+    24: 23,
+    29: 28
+}
+
+QL_LC_energy_slicers = [slice(1, 7), slice(
+    7, 12), slice(12, 17), slice(17, 23), slice(23, 28)]
+# energy slicer
+DETECTOR_GROUPS = [[1, 2], [6, 7], [5, 11], [12, 13], [14, 15], [10, 16],
+                   [8, 9], [3, 4], [31, 32], [26, 27], [22, 28], [20, 21],
+                   [18, 19], [17, 23], [24, 25], [29, 30]]
+DET_SIBLINGS = {
+    0: 1,
+    1: 0,
+    5: 6,
+    6: 5,
+    4: 10,
+    10: 4,
+    11: 12,
+    12: 11,
+    13: 14,
+    14: 13,
+    9: 15,
+    15: 9,
+    7: 8,
+    8: 7,
+    2: 3,
+    3: 2,
+    30: 31,
+    31: 30,
+    25: 26,
+    26: 25,
+    21: 27,
+    27: 21,
+    19: 20,
+    20: 19,
+    17: 18,
+    18: 17,
+    16: 22,
+    22: 16,
+    23: 24,
+    24: 23,
+    28: 29,
+    29: 28
+}
+
+det_id_to_trig_idx={0: 0,
+ 1: 0,
+ 2: 7,
+ 3: 7,
+ 4: 2,
+ 5: 1,
+ 6: 1,
+ 7: 6,
+ 8: 6,
+ 9: 5,
+ 10: 2,
+ 11: 3,
+ 12: 3,
+ 13: 4,
+ 14: 4,
+ 15: 5,
+ 16: 13,
+ 17: 12,
+ 18: 12,
+ 19: 11,
+ 20: 11,
+ 21: 10,
+ 22: 13,
+ 23: 14,
+ 24: 14,
+ 25: 9,
+ 26: 9,
+ 27: 10,
+ 28: 15,
+ 29: 15,
+ 30: 8,
+ 31: 8}
+
+def detector_id_to_trigger_index(i):
+    return det_id_to_trig_idx[i]
+
+def get_detector_in_same_group(idx):
+    """Get detector index in the same group
+    Args:
+        idx: int
+            detector id, detector id range: [0,31]
+    Returns
+        idx: int
+            ID of the detector in the same group
+    """
+    return detector_pairs.get(idx, None)
+
+
+def get_trigger_index(idx: int):
+    w = np.where(detector_ids_in_trigger_accumulators == idx)
+    return w[0][0]
+
+
+def get_trigger_acc_detector_ids():
+    return detector_ids_in_trigger_accumulators
+
+
+def get_sci_ebins(a, b):
+    low = np.where(ebin_low_edges == a)[0][0]
+    up = np.where(ebin_low_edges == b)[0][0]-1
+
+    return (low, up)
+
+
+
+
+
+
+
+

Functions

+
+
+def detector_id_to_trigger_index(i) +
+
+
+
+ +Expand source code + +
def detector_id_to_trigger_index(i):
+    return det_id_to_trig_idx[i]
+
+
+
+def get_detector_in_same_group(idx) +
+
+

Get detector index in the same group

+

Args

+
+
idx
+
int +detector id, detector id range: [0,31]
+
+

Returns +idx: int +ID of the detector in the same group

+
+ +Expand source code + +
def get_detector_in_same_group(idx):
+    """Get detector index in the same group
+    Args:
+        idx: int
+            detector id, detector id range: [0,31]
+    Returns
+        idx: int
+            ID of the detector in the same group
+    """
+    return detector_pairs.get(idx, None)
+
+
+
+def get_sci_ebins(a, b) +
+
+
+
+ +Expand source code + +
def get_sci_ebins(a, b):
+    low = np.where(ebin_low_edges == a)[0][0]
+    up = np.where(ebin_low_edges == b)[0][0]-1
+
+    return (low, up)
+
+
+
+def get_trigger_acc_detector_ids() +
+
+
+
+ +Expand source code + +
def get_trigger_acc_detector_ids():
+    return detector_ids_in_trigger_accumulators
+
+
+
+def get_trigger_index(idx: int) +
+
+
+
+ +Expand source code + +
def get_trigger_index(idx: int):
+    w = np.where(detector_ids_in_trigger_accumulators == idx)
+    return w[0][0]
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/io.html b/docs/stixdcpy/io.html new file mode 100644 index 0000000..b5a96dc --- /dev/null +++ b/docs/stixdcpy/io.html @@ -0,0 +1,287 @@ + + + + + + +stixdcpy.io API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.io

+
+
+
+ +Expand source code + +
#!/usr/bin/python
+import joblib
+import numpy as np
+import pandas as pd
+
+from stixdcpy.logger import logger
+'''
+    Methods in this module allow to save/load  objects to/from  npy  files
+
+    Author: Hualin Xiao (hualin.xiao@fhnw.ch)
+    Date: Sep. 1, 2021
+
+'''
+ALLOWED_EXTENSIONS = ['.pickle', '.npy', '.h5', '.fits']
+
+
+class IO(object):
+    """
+        Base object
+    """
+
+    def __init__(self):
+        pass
+
+    def dump(self, data, filename):
+        """Dump object to joblib file
+        Args
+            data: object
+                data object
+            filename: str
+                filename
+
+        Returns:
+            filename: str
+                filename
+        """
+        joblib.dump(data, filename)
+        return filename
+        #logger.error("this feature has not been implemented!")
+        # pass
+
+    def load(self, filename):
+        """load object from file
+
+        Args:
+            filename:  str
+
+        Returns:
+            data: object
+
+
+        """
+        return joblib.load(filename)
+        #logger.error("this feature has not been implemented!")
+        # pass
+
+    def to_pandas(self):
+        if self.data:
+            return pd.DataFrame(self.data)
+        return None
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class IO +
+
+

Base object

+
+ +Expand source code + +
class IO(object):
+    """
+        Base object
+    """
+
+    def __init__(self):
+        pass
+
+    def dump(self, data, filename):
+        """Dump object to joblib file
+        Args
+            data: object
+                data object
+            filename: str
+                filename
+
+        Returns:
+            filename: str
+                filename
+        """
+        joblib.dump(data, filename)
+        return filename
+        #logger.error("this feature has not been implemented!")
+        # pass
+
+    def load(self, filename):
+        """load object from file
+
+        Args:
+            filename:  str
+
+        Returns:
+            data: object
+
+
+        """
+        return joblib.load(filename)
+        #logger.error("this feature has not been implemented!")
+        # pass
+
+    def to_pandas(self):
+        if self.data:
+            return pd.DataFrame(self.data)
+        return None
+
+

Subclasses

+ +

Methods

+
+
+def dump(self, data, filename) +
+
+

Dump object to joblib file +Args +data: object +data object +filename: str +filename

+

Returns

+
+
filename
+
str +filename
+
+
+ +Expand source code + +
def dump(self, data, filename):
+    """Dump object to joblib file
+    Args
+        data: object
+            data object
+        filename: str
+            filename
+
+    Returns:
+        filename: str
+            filename
+    """
+    joblib.dump(data, filename)
+    return filename
+    #logger.error("this feature has not been implemented!")
+    # pass
+
+
+
+def load(self, filename) +
+
+

load object from file

+

Args

+
+
filename
+
str
+
+

Returns

+
+
data
+
object
+
+
+ +Expand source code + +
def load(self, filename):
+    """load object from file
+
+    Args:
+        filename:  str
+
+    Returns:
+        data: object
+
+
+    """
+    return joblib.load(filename)
+    #logger.error("this feature has not been implemented!")
+    # pass
+
+
+
+def to_pandas(self) +
+
+
+
+ +Expand source code + +
def to_pandas(self):
+    if self.data:
+        return pd.DataFrame(self.data)
+    return None
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/logger.html b/docs/stixdcpy/logger.html new file mode 100644 index 0000000..7e23638 --- /dev/null +++ b/docs/stixdcpy/logger.html @@ -0,0 +1,61 @@ + + + + + + +stixdcpy.logger API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.logger

+
+
+
+ +Expand source code + +
import logging
+logger = logging.getLogger('stixdcpy')
+logger.setLevel(logging.DEBUG)
+
+
+
+
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/net.html b/docs/stixdcpy/net.html new file mode 100644 index 0000000..f227860 --- /dev/null +++ b/docs/stixdcpy/net.html @@ -0,0 +1,1509 @@ + + + + + + +stixdcpy.net API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.net

+
+
+

This module provides APIs to retrieve data from STIX data center +Author: Hualin Xiao (hualin.xiao@fhnw.ch) +Date: Sep. 1, 2021

+
+ +Expand source code + +
#!/usr/bin/python
+"""
+    This module provides APIs to retrieve data from STIX data center
+    Author: Hualin Xiao (hualin.xiao@fhnw.ch)
+    Date: Sep. 1, 2021
+
+"""
+
+import hashlib
+
+import numpy as np
+import pandas as pd
+import pprint
+from pathlib import Path, PurePath
+from dateutil import parser as dtparser
+
+import requests
+from astropy.io import fits
+from tqdm import tqdm
+
+DOWNLOAD_PATH = Path.cwd() / 'downloads'
+DOWNLOAD_PATH.mkdir(parents=False, exist_ok=True)
+HOST = 'https://datacenter.stix.i4ds.net'
+#HOST='http://localhost:5000'
+URLS_POST = {
+    'LC': f'{HOST}/api/request/ql/lightcurves',
+    'HK': f'{HOST}/api/request/housekeeping',
+    'HK2': f'{HOST}/api/request/hk2',
+    'ELUT': f'{HOST}/api/request/eluts',
+    'EPHEMERIS': f'{HOST}/api/request/ephemeris',
+    'ATTITUDE': f'{HOST}/api/request/solo/attitude',
+    'SCIENCE': f'{HOST}/api/request/science-data/id',
+    'TRANSMISSION': f'{HOST}/api/request/transmission',
+    'FLARE_LIST': f'{HOST}/api/request/flare-list',
+    'STIX_POINTING': f'{HOST}/api/request/stixfov',
+    'CFL_SOLVER': f'{HOST}/api/request/solve/cfl'
+}
+
+FITS_TYPES = {
+    'l0', 'l1', 'l2', 'l3', 'spec', 'qlspec', 'asp', 'aspect', 'lc', 'bkg',
+    'var', 'ffl', 'cal', 'hkmin', 'hkmax'
+}
+
+
+class FitsQueryResult(object):
+    def __init__(self, resp):
+        self.hdu_objects = []
+        self.result = resp
+        self.downloaded_fits_files = []
+
+    def __repr__(self):
+        return str(self.result)
+
+    def __getitem__(self, index):
+        return self.result[index]
+
+    def __getattr__(self, name):
+        if name in ['num', 'len']:
+            return len(self.result)
+        elif name == 'hduls':
+            return self.hdu_objects
+
+    def __len__(self):
+        return len(self.result)
+
+    def pprint(self):
+        pprint.pprint(self.result)
+
+    def to_pandas(self):
+        return pd.DataFrame(self.result)
+
+    def open_fits(self):
+        self.hdu_objects = []
+        for filename in self.downloaded_fits_files:
+            self.hdu_objects.append(fits.open(filename))
+        return self.hdu_objects
+
+    def fits_info(self):
+        for hdu in self.hdu_objects:
+            print(hdu.info())
+
+    def get_fits_ids(self):
+        return [row['fits_id'] for row in self.result]
+
+    def fetch(self):
+        if self.result:
+            self.downloaded_fits_files = FitsQuery.fetch(self.result)
+            return self.downloaded_fits_files
+        else:
+            print('WARNING: Nothing to be downloaded from stix data center!')
+
+
+class FitsQuery(object):
+    """
+    Request FITS format data from STIX data center
+    """
+    def __init__(self):
+        self.fits_file_list = []
+
+    @staticmethod
+    def wget(url: str, desc: str, progress_bar=True):
+        """Download a file from the link and save the file to a temporary file.
+           Downloading progress will be shown in a progress bar
+
+        Args:
+            url (str): URL
+            desc (str): description to be shown on the progress bar
+
+        Returns:
+            temporary filename 
+        """
+        stream = progress_bar
+        resp = requests.get(url, stream=stream)
+        content_type = resp.headers.get('content-type')
+        if content_type != 'binary/x-fits':
+            print('ERROR:', resp.content)
+            return None
+
+        folder = DOWNLOAD_PATH
+        try:
+            fname = resp.headers.get("Content-Disposition").split(
+                "filename=")[1]
+        except AttributeError:
+            md5hex = hashlib.md5(url.encode('utf-8')).hexdigest()
+            fname = f'{md5hex}.fits'
+        filename = PurePath(folder, fname)
+        file_path = Path(filename)
+        if file_path.is_file():
+            print(f'Found the data in local storage. Filename: {filename} ...')
+            return str(file_path)
+        f = open(filename, 'wb')
+        chunk_size = 1024
+        total = int(resp.headers.get('content-length', 0))
+        with tqdm(
+                desc=desc,
+                total=total,
+                unit='iB',
+                unit_scale=True,
+                unit_divisor=chunk_size,
+        ) as bar:
+            for data in resp.iter_content(chunk_size=chunk_size):
+                size = f.write(data)
+                bar.update(size)
+        name = f.name
+        f.close()
+        return name
+
+    @staticmethod
+    def query(start_utc, stop_utc, product_type='lc'):
+        if product_type not in FITS_TYPES:
+            raise TypeError(
+                f'Invalid product type! product_type can be one of {str(FITS_TYPES)}'
+            )
+        url = f'{HOST}/query/fits/{start_utc}/{stop_utc}/{product_type}'
+        r = requests.get(url).json()
+        res = []
+        if isinstance(r, list):
+            res = r
+        elif 'error' in r:
+            print(r['error'])
+        return FitsQueryResult(res)
+
+    @staticmethod
+    def fetch_bulk_science_by_request_id(request_id):
+        url = f'{HOST}/download/fits/bsd/{request_id}'
+        fname = FitsQuery.wget(url, f'Downloading STIX Science data #{request_id}')
+        return fname
+
+    @staticmethod
+    def fetch(query_results):
+        fits_ids = []
+        if isinstance(query_results, FitsQueryResult):
+            fits_ids = query_results.get_fits_ids()
+        elif isinstance(query_results, int):
+            fits_ids = [query_results]
+        elif isinstance(query_results, list):
+            try:
+                fits_ids = [row['fits_id'] for row in query_results]
+            except Exception as e:
+                pass
+            if not fits_ids:
+                try:
+                    fits_ids = [
+                        row for row in query_results if isinstance(row, int)
+                    ]
+                except:
+                    pass
+        if not fits_ids:
+            raise TypeError('Invalid argument type')
+
+        fits_filenames = []
+        try:
+            for file_id in fits_ids:
+                fname = FitsQuery.get_fits(file_id)
+                fits_filenames.append(fname)
+        except Exception as e:
+            raise e
+        # self.fits_file_list=fits_filenames
+        return fits_filenames
+
+    @staticmethod
+    def get_fits(fits_id, progress_bar=True):
+        """Download FITS data products from STIX data center.
+        Args:
+            fits_id: FITS file ID
+            progress_bar: show the progress bar if it is true
+
+
+        Returns:
+            A FITS hdulist object if success;  None if failed
+        """
+        url = f'{HOST}/download/fits/{fits_id}'
+        fname = FitsQuery.wget(url, 'Downloading data', progress_bar)
+        return fname
+
+    @staticmethod
+    def fetch_continuous_data(start_utc, end_utc, data_type):
+        if data_type not in ['hkmax', 'lc', 'var', 'qlspec', 'bkg']:
+            raise TypeError(f'Data type {data_type} not supported!')
+        url = f'{HOST}/create/fits/{start_utc}/{end_utc}/{data_type}'
+        fname = FitsQuery.wget(url, 'Downloading data', True)
+        return fname
+
+
+class JSONRequest(object):
+    """Request json format data from STIX data center """
+    @staticmethod
+    def post(url, form):
+        response = requests.post(url, data=form)
+        data = response.json()
+
+        if 'error' in data:
+            if data['error']:
+                return None
+        return data
+
+    @staticmethod
+    def fetch_light_curves(begin_utc: str, end_utc: str, ltc: bool):
+        """ Request light curve from STIX data center
+
+        Args:
+            begin_utc:  str
+                Observation start time
+            end_utc: str
+                Observation end time
+            ltc: bool, optional
+                Light time correction enabling flag.   Do light time correction if True
+        Returns:
+            lightcurve: dict
+                A python dictionary containing light curve data
+
+        """
+        form = {'begin': begin_utc, 'ltc': ltc, 'end': end_utc}
+        url = URLS_POST['LC']
+        return JSONRequest.post(url, form)
+
+    @staticmethod
+    def fetch_housekeeping(begin_utc: str, end_utc: str):
+        """Fetch housekeeping data from STIX data center
+
+        Args:
+            begin_utc: Data start time
+            end_utc: data end time
+
+        Returns:
+            result:  dict
+            housekeeping data
+
+        """
+        if not begin_utc.endswith('Z'):
+            begin_utc += 'Z'
+        if not end_utc.endswith('Z'):
+            end_utc += 'Z'
+        start_unix = dtparser.parse(begin_utc).timestamp()
+        end_unix = dtparser.parse(end_utc).timestamp()
+        duration = int(end_unix) - int(start_unix)
+        form = {
+            'start_unix': start_unix,
+            'duration': duration,
+        }
+        url = URLS_POST['HK']
+        return JSONRequest.post(url, form)
+
+    @staticmethod
+    def solve_cfl(cfl_counts, cfl_counts_err, fluence, fluence_err):
+        """compute flare location using the online flare location solver
+
+        Args:
+            cfl_counts: numpy array or list
+                counts recorded by the 12 CFL pixels
+            cfl_counts_err:  numpy array or list
+                standard deviations of  the counts recorded by the 12 CFL pixels
+            fluence: float
+                X-ray fluence in units of  counts/mm2,  calculated using counts recorded by other detectors
+            fluence_err: float
+                Errors in fluence in counts/mm2 units
+        Returns:
+            location: dict
+                CFL location, ephemeris and the chisquare map
+
+        """
+        form = {'counts': cfl_counts, 'counts_err':cfl_counts_err,
+                'fluence':fluence,'fluence_err':fluence_err}
+        url = URLS_POST['CFL_SOLVER']
+        return JSONRequest.post(url, form)
+
+    @staticmethod
+    def fetch_elut(utc):
+        """Download ELUT from STIX data center
+        Args:
+            utc: Time
+        Returns: dict
+            object: a diction string containing elut information
+        """
+        form = {'utc': utc}
+        url = URLS_POST['ELUT']
+        return JSONRequest.post(url, form)
+
+    @staticmethod
+    def request_ephemeris(start_utc: str, end_utc: str, steps=1):
+        return JSONRequest.post(URLS_POST['EPHEMERIS'], {
+            'start_utc': start_utc,
+            'end_utc': end_utc,
+            'steps': steps
+        })
+    @staticmethod
+    def request_pointing(utc: str):
+        return JSONRequest.post(URLS_POST['STIX_POINTING'], {
+            'utc': utc,
+        })
+    @staticmethod
+    def request_attitude(start_utc: str, end_utc: str,  steps=1, instrument_frame='SOLO_SRF', ref_frame='SOLO_SUN_RTN'):
+        form={
+            'start_utc': start_utc,
+            'end_utc': end_utc,
+            'steps': steps,
+            'frame1':instrument_frame,
+            'frame2':ref_frame
+        }
+        ret=JSONRequest.post(URLS_POST['ATTITUDE'], form)
+        return ret
+    @staticmethod
+    def fetch_science_data(_id: int):
+        """fetch science data from stix data center
+
+        Args:
+            _id: int
+                science data unique ID, which can be found on STIX data center bulk science data web page
+
+
+        Returns:
+            science_data: dict
+                science data received from data center if success or None if failed
+
+        """
+        return JSONRequest.post(URLS_POST['SCIENCE'], {
+            'id': _id,
+        })
+
+    @staticmethod
+    def fetch_flare_list(start_utc: str, end_utc: str, sort: str = 'time'):
+        """ query and download flare list from stix data center
+
+        Args:
+            start_utc: str
+                flare start UTC
+            end_utc: str
+                flare end UTC
+            sort: str
+                key to sort flares. It can be one of ['goes','time', 'LC0','LC1','LC2','LC3','LC4], LCi here means the i-th QL light curve
+
+
+        Returns:
+            flare_list: dict or None
+                flare list if success or None if failed.
+
+        """
+        return JSONRequest.post(URLS_POST['FLARE_LIST'], {
+            'start_utc': start_utc,
+            'end_utc': end_utc,
+            'sort': sort
+        })
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class FitsQuery +
+
+

Request FITS format data from STIX data center

+
+ +Expand source code + +
class FitsQuery(object):
+    """
+    Request FITS format data from STIX data center
+    """
+    def __init__(self):
+        self.fits_file_list = []
+
+    @staticmethod
+    def wget(url: str, desc: str, progress_bar=True):
+        """Download a file from the link and save the file to a temporary file.
+           Downloading progress will be shown in a progress bar
+
+        Args:
+            url (str): URL
+            desc (str): description to be shown on the progress bar
+
+        Returns:
+            temporary filename 
+        """
+        stream = progress_bar
+        resp = requests.get(url, stream=stream)
+        content_type = resp.headers.get('content-type')
+        if content_type != 'binary/x-fits':
+            print('ERROR:', resp.content)
+            return None
+
+        folder = DOWNLOAD_PATH
+        try:
+            fname = resp.headers.get("Content-Disposition").split(
+                "filename=")[1]
+        except AttributeError:
+            md5hex = hashlib.md5(url.encode('utf-8')).hexdigest()
+            fname = f'{md5hex}.fits'
+        filename = PurePath(folder, fname)
+        file_path = Path(filename)
+        if file_path.is_file():
+            print(f'Found the data in local storage. Filename: {filename} ...')
+            return str(file_path)
+        f = open(filename, 'wb')
+        chunk_size = 1024
+        total = int(resp.headers.get('content-length', 0))
+        with tqdm(
+                desc=desc,
+                total=total,
+                unit='iB',
+                unit_scale=True,
+                unit_divisor=chunk_size,
+        ) as bar:
+            for data in resp.iter_content(chunk_size=chunk_size):
+                size = f.write(data)
+                bar.update(size)
+        name = f.name
+        f.close()
+        return name
+
+    @staticmethod
+    def query(start_utc, stop_utc, product_type='lc'):
+        if product_type not in FITS_TYPES:
+            raise TypeError(
+                f'Invalid product type! product_type can be one of {str(FITS_TYPES)}'
+            )
+        url = f'{HOST}/query/fits/{start_utc}/{stop_utc}/{product_type}'
+        r = requests.get(url).json()
+        res = []
+        if isinstance(r, list):
+            res = r
+        elif 'error' in r:
+            print(r['error'])
+        return FitsQueryResult(res)
+
+    @staticmethod
+    def fetch_bulk_science_by_request_id(request_id):
+        url = f'{HOST}/download/fits/bsd/{request_id}'
+        fname = FitsQuery.wget(url, f'Downloading STIX Science data #{request_id}')
+        return fname
+
+    @staticmethod
+    def fetch(query_results):
+        fits_ids = []
+        if isinstance(query_results, FitsQueryResult):
+            fits_ids = query_results.get_fits_ids()
+        elif isinstance(query_results, int):
+            fits_ids = [query_results]
+        elif isinstance(query_results, list):
+            try:
+                fits_ids = [row['fits_id'] for row in query_results]
+            except Exception as e:
+                pass
+            if not fits_ids:
+                try:
+                    fits_ids = [
+                        row for row in query_results if isinstance(row, int)
+                    ]
+                except:
+                    pass
+        if not fits_ids:
+            raise TypeError('Invalid argument type')
+
+        fits_filenames = []
+        try:
+            for file_id in fits_ids:
+                fname = FitsQuery.get_fits(file_id)
+                fits_filenames.append(fname)
+        except Exception as e:
+            raise e
+        # self.fits_file_list=fits_filenames
+        return fits_filenames
+
+    @staticmethod
+    def get_fits(fits_id, progress_bar=True):
+        """Download FITS data products from STIX data center.
+        Args:
+            fits_id: FITS file ID
+            progress_bar: show the progress bar if it is true
+
+
+        Returns:
+            A FITS hdulist object if success;  None if failed
+        """
+        url = f'{HOST}/download/fits/{fits_id}'
+        fname = FitsQuery.wget(url, 'Downloading data', progress_bar)
+        return fname
+
+    @staticmethod
+    def fetch_continuous_data(start_utc, end_utc, data_type):
+        if data_type not in ['hkmax', 'lc', 'var', 'qlspec', 'bkg']:
+            raise TypeError(f'Data type {data_type} not supported!')
+        url = f'{HOST}/create/fits/{start_utc}/{end_utc}/{data_type}'
+        fname = FitsQuery.wget(url, 'Downloading data', True)
+        return fname
+
+

Static methods

+
+
+def fetch(query_results) +
+
+
+
+ +Expand source code + +
@staticmethod
+def fetch(query_results):
+    fits_ids = []
+    if isinstance(query_results, FitsQueryResult):
+        fits_ids = query_results.get_fits_ids()
+    elif isinstance(query_results, int):
+        fits_ids = [query_results]
+    elif isinstance(query_results, list):
+        try:
+            fits_ids = [row['fits_id'] for row in query_results]
+        except Exception as e:
+            pass
+        if not fits_ids:
+            try:
+                fits_ids = [
+                    row for row in query_results if isinstance(row, int)
+                ]
+            except:
+                pass
+    if not fits_ids:
+        raise TypeError('Invalid argument type')
+
+    fits_filenames = []
+    try:
+        for file_id in fits_ids:
+            fname = FitsQuery.get_fits(file_id)
+            fits_filenames.append(fname)
+    except Exception as e:
+        raise e
+    # self.fits_file_list=fits_filenames
+    return fits_filenames
+
+
+
+def fetch_bulk_science_by_request_id(request_id) +
+
+
+
+ +Expand source code + +
@staticmethod
+def fetch_bulk_science_by_request_id(request_id):
+    url = f'{HOST}/download/fits/bsd/{request_id}'
+    fname = FitsQuery.wget(url, f'Downloading STIX Science data #{request_id}')
+    return fname
+
+
+
+def fetch_continuous_data(start_utc, end_utc, data_type) +
+
+
+
+ +Expand source code + +
@staticmethod
+def fetch_continuous_data(start_utc, end_utc, data_type):
+    if data_type not in ['hkmax', 'lc', 'var', 'qlspec', 'bkg']:
+        raise TypeError(f'Data type {data_type} not supported!')
+    url = f'{HOST}/create/fits/{start_utc}/{end_utc}/{data_type}'
+    fname = FitsQuery.wget(url, 'Downloading data', True)
+    return fname
+
+
+
+def get_fits(fits_id, progress_bar=True) +
+
+

Download FITS data products from STIX data center.

+

Args

+
+
fits_id
+
FITS file ID
+
progress_bar
+
show the progress bar if it is true
+
+

Returns

+

A FITS hdulist object if success; +None if failed

+
+ +Expand source code + +
@staticmethod
+def get_fits(fits_id, progress_bar=True):
+    """Download FITS data products from STIX data center.
+    Args:
+        fits_id: FITS file ID
+        progress_bar: show the progress bar if it is true
+
+
+    Returns:
+        A FITS hdulist object if success;  None if failed
+    """
+    url = f'{HOST}/download/fits/{fits_id}'
+    fname = FitsQuery.wget(url, 'Downloading data', progress_bar)
+    return fname
+
+
+
+def query(start_utc, stop_utc, product_type='lc') +
+
+
+
+ +Expand source code + +
@staticmethod
+def query(start_utc, stop_utc, product_type='lc'):
+    if product_type not in FITS_TYPES:
+        raise TypeError(
+            f'Invalid product type! product_type can be one of {str(FITS_TYPES)}'
+        )
+    url = f'{HOST}/query/fits/{start_utc}/{stop_utc}/{product_type}'
+    r = requests.get(url).json()
+    res = []
+    if isinstance(r, list):
+        res = r
+    elif 'error' in r:
+        print(r['error'])
+    return FitsQueryResult(res)
+
+
+
+def wget(url: str, desc: str, progress_bar=True) +
+
+

Download a file from the link and save the file to a temporary file. +Downloading progress will be shown in a progress bar

+

Args

+
+
url : str
+
URL
+
desc : str
+
description to be shown on the progress bar
+
+

Returns

+

temporary filename

+
+ +Expand source code + +
@staticmethod
+def wget(url: str, desc: str, progress_bar=True):
+    """Download a file from the link and save the file to a temporary file.
+       Downloading progress will be shown in a progress bar
+
+    Args:
+        url (str): URL
+        desc (str): description to be shown on the progress bar
+
+    Returns:
+        temporary filename 
+    """
+    stream = progress_bar
+    resp = requests.get(url, stream=stream)
+    content_type = resp.headers.get('content-type')
+    if content_type != 'binary/x-fits':
+        print('ERROR:', resp.content)
+        return None
+
+    folder = DOWNLOAD_PATH
+    try:
+        fname = resp.headers.get("Content-Disposition").split(
+            "filename=")[1]
+    except AttributeError:
+        md5hex = hashlib.md5(url.encode('utf-8')).hexdigest()
+        fname = f'{md5hex}.fits'
+    filename = PurePath(folder, fname)
+    file_path = Path(filename)
+    if file_path.is_file():
+        print(f'Found the data in local storage. Filename: {filename} ...')
+        return str(file_path)
+    f = open(filename, 'wb')
+    chunk_size = 1024
+    total = int(resp.headers.get('content-length', 0))
+    with tqdm(
+            desc=desc,
+            total=total,
+            unit='iB',
+            unit_scale=True,
+            unit_divisor=chunk_size,
+    ) as bar:
+        for data in resp.iter_content(chunk_size=chunk_size):
+            size = f.write(data)
+            bar.update(size)
+    name = f.name
+    f.close()
+    return name
+
+
+
+
+
+class FitsQueryResult +(resp) +
+
+
+
+ +Expand source code + +
class FitsQueryResult(object):
+    def __init__(self, resp):
+        self.hdu_objects = []
+        self.result = resp
+        self.downloaded_fits_files = []
+
+    def __repr__(self):
+        return str(self.result)
+
+    def __getitem__(self, index):
+        return self.result[index]
+
+    def __getattr__(self, name):
+        if name in ['num', 'len']:
+            return len(self.result)
+        elif name == 'hduls':
+            return self.hdu_objects
+
+    def __len__(self):
+        return len(self.result)
+
+    def pprint(self):
+        pprint.pprint(self.result)
+
+    def to_pandas(self):
+        return pd.DataFrame(self.result)
+
+    def open_fits(self):
+        self.hdu_objects = []
+        for filename in self.downloaded_fits_files:
+            self.hdu_objects.append(fits.open(filename))
+        return self.hdu_objects
+
+    def fits_info(self):
+        for hdu in self.hdu_objects:
+            print(hdu.info())
+
+    def get_fits_ids(self):
+        return [row['fits_id'] for row in self.result]
+
+    def fetch(self):
+        if self.result:
+            self.downloaded_fits_files = FitsQuery.fetch(self.result)
+            return self.downloaded_fits_files
+        else:
+            print('WARNING: Nothing to be downloaded from stix data center!')
+
+

Methods

+
+
+def fetch(self) +
+
+
+
+ +Expand source code + +
def fetch(self):
+    if self.result:
+        self.downloaded_fits_files = FitsQuery.fetch(self.result)
+        return self.downloaded_fits_files
+    else:
+        print('WARNING: Nothing to be downloaded from stix data center!')
+
+
+
+def fits_info(self) +
+
+
+
+ +Expand source code + +
def fits_info(self):
+    for hdu in self.hdu_objects:
+        print(hdu.info())
+
+
+
+def get_fits_ids(self) +
+
+
+
+ +Expand source code + +
def get_fits_ids(self):
+    return [row['fits_id'] for row in self.result]
+
+
+
+def open_fits(self) +
+
+
+
+ +Expand source code + +
def open_fits(self):
+    self.hdu_objects = []
+    for filename in self.downloaded_fits_files:
+        self.hdu_objects.append(fits.open(filename))
+    return self.hdu_objects
+
+
+
+def pprint(self) +
+
+
+
+ +Expand source code + +
def pprint(self):
+    pprint.pprint(self.result)
+
+
+
+def to_pandas(self) +
+
+
+
+ +Expand source code + +
def to_pandas(self):
+    return pd.DataFrame(self.result)
+
+
+
+
+
+class JSONRequest +
+
+

Request json format data from STIX data center

+
+ +Expand source code + +
class JSONRequest(object):
+    """Request json format data from STIX data center """
+    @staticmethod
+    def post(url, form):
+        response = requests.post(url, data=form)
+        data = response.json()
+
+        if 'error' in data:
+            if data['error']:
+                return None
+        return data
+
+    @staticmethod
+    def fetch_light_curves(begin_utc: str, end_utc: str, ltc: bool):
+        """ Request light curve from STIX data center
+
+        Args:
+            begin_utc:  str
+                Observation start time
+            end_utc: str
+                Observation end time
+            ltc: bool, optional
+                Light time correction enabling flag.   Do light time correction if True
+        Returns:
+            lightcurve: dict
+                A python dictionary containing light curve data
+
+        """
+        form = {'begin': begin_utc, 'ltc': ltc, 'end': end_utc}
+        url = URLS_POST['LC']
+        return JSONRequest.post(url, form)
+
+    @staticmethod
+    def fetch_housekeeping(begin_utc: str, end_utc: str):
+        """Fetch housekeeping data from STIX data center
+
+        Args:
+            begin_utc: Data start time
+            end_utc: data end time
+
+        Returns:
+            result:  dict
+            housekeeping data
+
+        """
+        if not begin_utc.endswith('Z'):
+            begin_utc += 'Z'
+        if not end_utc.endswith('Z'):
+            end_utc += 'Z'
+        start_unix = dtparser.parse(begin_utc).timestamp()
+        end_unix = dtparser.parse(end_utc).timestamp()
+        duration = int(end_unix) - int(start_unix)
+        form = {
+            'start_unix': start_unix,
+            'duration': duration,
+        }
+        url = URLS_POST['HK']
+        return JSONRequest.post(url, form)
+
+    @staticmethod
+    def solve_cfl(cfl_counts, cfl_counts_err, fluence, fluence_err):
+        """compute flare location using the online flare location solver
+
+        Args:
+            cfl_counts: numpy array or list
+                counts recorded by the 12 CFL pixels
+            cfl_counts_err:  numpy array or list
+                standard deviations of  the counts recorded by the 12 CFL pixels
+            fluence: float
+                X-ray fluence in units of  counts/mm2,  calculated using counts recorded by other detectors
+            fluence_err: float
+                Errors in fluence in counts/mm2 units
+        Returns:
+            location: dict
+                CFL location, ephemeris and the chisquare map
+
+        """
+        form = {'counts': cfl_counts, 'counts_err':cfl_counts_err,
+                'fluence':fluence,'fluence_err':fluence_err}
+        url = URLS_POST['CFL_SOLVER']
+        return JSONRequest.post(url, form)
+
+    @staticmethod
+    def fetch_elut(utc):
+        """Download ELUT from STIX data center
+        Args:
+            utc: Time
+        Returns: dict
+            object: a diction string containing elut information
+        """
+        form = {'utc': utc}
+        url = URLS_POST['ELUT']
+        return JSONRequest.post(url, form)
+
+    @staticmethod
+    def request_ephemeris(start_utc: str, end_utc: str, steps=1):
+        return JSONRequest.post(URLS_POST['EPHEMERIS'], {
+            'start_utc': start_utc,
+            'end_utc': end_utc,
+            'steps': steps
+        })
+    @staticmethod
+    def request_pointing(utc: str):
+        return JSONRequest.post(URLS_POST['STIX_POINTING'], {
+            'utc': utc,
+        })
+    @staticmethod
+    def request_attitude(start_utc: str, end_utc: str,  steps=1, instrument_frame='SOLO_SRF', ref_frame='SOLO_SUN_RTN'):
+        form={
+            'start_utc': start_utc,
+            'end_utc': end_utc,
+            'steps': steps,
+            'frame1':instrument_frame,
+            'frame2':ref_frame
+        }
+        ret=JSONRequest.post(URLS_POST['ATTITUDE'], form)
+        return ret
+    @staticmethod
+    def fetch_science_data(_id: int):
+        """fetch science data from stix data center
+
+        Args:
+            _id: int
+                science data unique ID, which can be found on STIX data center bulk science data web page
+
+
+        Returns:
+            science_data: dict
+                science data received from data center if success or None if failed
+
+        """
+        return JSONRequest.post(URLS_POST['SCIENCE'], {
+            'id': _id,
+        })
+
+    @staticmethod
+    def fetch_flare_list(start_utc: str, end_utc: str, sort: str = 'time'):
+        """ query and download flare list from stix data center
+
+        Args:
+            start_utc: str
+                flare start UTC
+            end_utc: str
+                flare end UTC
+            sort: str
+                key to sort flares. It can be one of ['goes','time', 'LC0','LC1','LC2','LC3','LC4], LCi here means the i-th QL light curve
+
+
+        Returns:
+            flare_list: dict or None
+                flare list if success or None if failed.
+
+        """
+        return JSONRequest.post(URLS_POST['FLARE_LIST'], {
+            'start_utc': start_utc,
+            'end_utc': end_utc,
+            'sort': sort
+        })
+
+

Static methods

+
+
+def fetch_elut(utc) +
+
+

Download ELUT from STIX data center

+

Args

+
+
utc
+
Time
+
+

Returns: dict +object: a diction string containing elut information

+
+ +Expand source code + +
@staticmethod
+def fetch_elut(utc):
+    """Download ELUT from STIX data center
+    Args:
+        utc: Time
+    Returns: dict
+        object: a diction string containing elut information
+    """
+    form = {'utc': utc}
+    url = URLS_POST['ELUT']
+    return JSONRequest.post(url, form)
+
+
+
+def fetch_flare_list(start_utc: str, end_utc: str, sort: str = 'time') +
+
+

query and download flare list from stix data center

+

Args

+
+
start_utc
+
str +flare start UTC
+
end_utc
+
str +flare end UTC
+
sort
+
str +key to sort flares. It can be one of ['goes','time', 'LC0','LC1','LC2','LC3','LC4], LCi here means the i-th QL light curve
+
+

Returns

+
+
flare_list
+
dict or None +flare list if success or None if failed.
+
+
+ +Expand source code + +
@staticmethod
+def fetch_flare_list(start_utc: str, end_utc: str, sort: str = 'time'):
+    """ query and download flare list from stix data center
+
+    Args:
+        start_utc: str
+            flare start UTC
+        end_utc: str
+            flare end UTC
+        sort: str
+            key to sort flares. It can be one of ['goes','time', 'LC0','LC1','LC2','LC3','LC4], LCi here means the i-th QL light curve
+
+
+    Returns:
+        flare_list: dict or None
+            flare list if success or None if failed.
+
+    """
+    return JSONRequest.post(URLS_POST['FLARE_LIST'], {
+        'start_utc': start_utc,
+        'end_utc': end_utc,
+        'sort': sort
+    })
+
+
+
+def fetch_housekeeping(begin_utc: str, end_utc: str) +
+
+

Fetch housekeeping data from STIX data center

+

Args

+
+
begin_utc
+
Data start time
+
end_utc
+
data end time
+
+

Returns

+
+
result
+
dict
+
+

housekeeping data

+
+ +Expand source code + +
@staticmethod
+def fetch_housekeeping(begin_utc: str, end_utc: str):
+    """Fetch housekeeping data from STIX data center
+
+    Args:
+        begin_utc: Data start time
+        end_utc: data end time
+
+    Returns:
+        result:  dict
+        housekeeping data
+
+    """
+    if not begin_utc.endswith('Z'):
+        begin_utc += 'Z'
+    if not end_utc.endswith('Z'):
+        end_utc += 'Z'
+    start_unix = dtparser.parse(begin_utc).timestamp()
+    end_unix = dtparser.parse(end_utc).timestamp()
+    duration = int(end_unix) - int(start_unix)
+    form = {
+        'start_unix': start_unix,
+        'duration': duration,
+    }
+    url = URLS_POST['HK']
+    return JSONRequest.post(url, form)
+
+
+
+def fetch_light_curves(begin_utc: str, end_utc: str, ltc: bool) +
+
+

Request light curve from STIX data center

+

Args

+
+
begin_utc
+
str +Observation start time
+
end_utc
+
str +Observation end time
+
ltc
+
bool, optional +Light time correction enabling flag. +Do light time correction if True
+
+

Returns

+
+
lightcurve
+
dict +A python dictionary containing light curve data
+
+
+ +Expand source code + +
@staticmethod
+def fetch_light_curves(begin_utc: str, end_utc: str, ltc: bool):
+    """ Request light curve from STIX data center
+
+    Args:
+        begin_utc:  str
+            Observation start time
+        end_utc: str
+            Observation end time
+        ltc: bool, optional
+            Light time correction enabling flag.   Do light time correction if True
+    Returns:
+        lightcurve: dict
+            A python dictionary containing light curve data
+
+    """
+    form = {'begin': begin_utc, 'ltc': ltc, 'end': end_utc}
+    url = URLS_POST['LC']
+    return JSONRequest.post(url, form)
+
+
+
+def fetch_science_data(_id: int) +
+
+

fetch science data from stix data center

+

Args

+
+
_id
+
int +science data unique ID, which can be found on STIX data center bulk science data web page
+
+

Returns

+
+
science_data
+
dict +science data received from data center if success or None if failed
+
+
+ +Expand source code + +
@staticmethod
+def fetch_science_data(_id: int):
+    """fetch science data from stix data center
+
+    Args:
+        _id: int
+            science data unique ID, which can be found on STIX data center bulk science data web page
+
+
+    Returns:
+        science_data: dict
+            science data received from data center if success or None if failed
+
+    """
+    return JSONRequest.post(URLS_POST['SCIENCE'], {
+        'id': _id,
+    })
+
+
+
+def post(url, form) +
+
+
+
+ +Expand source code + +
@staticmethod
+def post(url, form):
+    response = requests.post(url, data=form)
+    data = response.json()
+
+    if 'error' in data:
+        if data['error']:
+            return None
+    return data
+
+
+
+def request_attitude(start_utc: str, end_utc: str, steps=1, instrument_frame='SOLO_SRF', ref_frame='SOLO_SUN_RTN') +
+
+
+
+ +Expand source code + +
@staticmethod
+def request_attitude(start_utc: str, end_utc: str,  steps=1, instrument_frame='SOLO_SRF', ref_frame='SOLO_SUN_RTN'):
+    form={
+        'start_utc': start_utc,
+        'end_utc': end_utc,
+        'steps': steps,
+        'frame1':instrument_frame,
+        'frame2':ref_frame
+    }
+    ret=JSONRequest.post(URLS_POST['ATTITUDE'], form)
+    return ret
+
+
+
+def request_ephemeris(start_utc: str, end_utc: str, steps=1) +
+
+
+
+ +Expand source code + +
@staticmethod
+def request_ephemeris(start_utc: str, end_utc: str, steps=1):
+    return JSONRequest.post(URLS_POST['EPHEMERIS'], {
+        'start_utc': start_utc,
+        'end_utc': end_utc,
+        'steps': steps
+    })
+
+
+
+def request_pointing(utc: str) +
+
+
+
+ +Expand source code + +
@staticmethod
+def request_pointing(utc: str):
+    return JSONRequest.post(URLS_POST['STIX_POINTING'], {
+        'utc': utc,
+    })
+
+
+
+def solve_cfl(cfl_counts, cfl_counts_err, fluence, fluence_err) +
+
+

compute flare location using the online flare location solver

+

Args

+
+
cfl_counts
+
numpy array or list +counts recorded by the 12 CFL pixels
+
cfl_counts_err
+
numpy array or list +standard deviations of +the counts recorded by the 12 CFL pixels
+
fluence
+
float +X-ray fluence in units of +counts/mm2, +calculated using counts recorded by other detectors
+
fluence_err
+
float +Errors in fluence in counts/mm2 units
+
+

Returns

+
+
location
+
dict +CFL location, ephemeris and the chisquare map
+
+
+ +Expand source code + +
@staticmethod
+def solve_cfl(cfl_counts, cfl_counts_err, fluence, fluence_err):
+    """compute flare location using the online flare location solver
+
+    Args:
+        cfl_counts: numpy array or list
+            counts recorded by the 12 CFL pixels
+        cfl_counts_err:  numpy array or list
+            standard deviations of  the counts recorded by the 12 CFL pixels
+        fluence: float
+            X-ray fluence in units of  counts/mm2,  calculated using counts recorded by other detectors
+        fluence_err: float
+            Errors in fluence in counts/mm2 units
+    Returns:
+        location: dict
+            CFL location, ephemeris and the chisquare map
+
+    """
+    form = {'counts': cfl_counts, 'counts_err':cfl_counts_err,
+            'fluence':fluence,'fluence_err':fluence_err}
+    url = URLS_POST['CFL_SOLVER']
+    return JSONRequest.post(url, form)
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/quicklook.html b/docs/stixdcpy/quicklook.html new file mode 100644 index 0000000..0020948 --- /dev/null +++ b/docs/stixdcpy/quicklook.html @@ -0,0 +1,452 @@ + + + + + + +stixdcpy.quicklook API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.quicklook

+
+
+

This module provides APIs to retrieve Quick-look data from STIX data center +,and some tools to display the data +Author: Hualin Xiao (hualin.xiao@fhnw.ch) +Date: Sep. 1, 2021

+
+ +Expand source code + +
#!/usr/bin/python
+"""
+    This module provides APIs to retrieve Quick-look data from STIX data center  ,and some tools to display the data
+    Author: Hualin Xiao (hualin.xiao@fhnw.ch)
+    Date: Sep. 1, 2021
+
+"""
+import datetime
+
+from matplotlib import pyplot as plt
+from stixdcpy import io as sio
+from stixdcpy.net import JSONRequest as jreq
+
+
+class QuickLook(sio.IO):
+    def __init__(self):
+        pass
+
+    # def save_fits(self,fname):
+    #    self.data.writeto(fname)
+
+
+class LightCurves(QuickLook):
+    def __init__(self, data):
+        if 'error' not in data:
+            self.data = data
+        else:
+            self.data = None
+
+    @classmethod
+    def from_sdc(cls, start_utc: str, end_utc: str, ltc=False):
+        """ fetch light curve data from STIX data center
+
+        Args:
+            start_utc: str
+                data start UTC
+            end_utc: str
+                data end UTC
+            ltc: bool
+                Light time correction flag. Do light time correction if it is True
+
+
+        Returns:
+            lc: python object
+                Lightcurve object
+
+        """
+        data = jreq.fetch_light_curves(start_utc, end_utc, ltc)
+        if 'light_curves' in data:
+            # correct key name
+            data['counts'] = data['light_curves']
+            del data['light_curves']
+        return cls(data)
+
+    def __getattr__(self, name):
+        if name == 'data':
+            return self.data
+
+    def get_data(self):
+        """ get light curve data
+        Returns:
+            data: dict
+                light curve data
+
+        """
+        return self.data
+
+    def peek(self, ax=None, legend_loc='upper right'):
+        """
+        Plot light curves
+        Args:
+            ltc: light time correction flag. The default value is False. Do light time correction if ltc=True
+        Returns
+            ax: matplotlib axs
+
+        """
+        if not self.data:
+            ax.text(0.5, 0.5, 'LC not available!')
+            return ax
+
+        if not ax:
+            _, ax = plt.subplots()
+        dt = [
+            datetime.datetime.utcfromtimestamp(t)
+            for t in self.data['unix_time']
+        ]
+        for i in range(5):
+            ax.plot(dt,
+                    self.data['counts'][str(i)],
+                    label=self.data['energy_bins']['names'][i])
+        dlt = self.data['DELTA_LIGHT_TIME']
+        light_time_corrected = self.data['IS_LIGHT_TIME_CORRECTED']
+
+        xlabel = f'UTC + {dlt:.2f} (4 sec time bins)' if light_time_corrected else 'UTC (4 sec time bins)'
+        ax.set_xlabel(xlabel)
+        ax.set_ylabel('Counts')
+        ax.legend(loc=legend_loc)
+        ax.set_yscale('log')
+        return ax
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class LightCurves +(data) +
+
+

Base object

+
+ +Expand source code + +
class LightCurves(QuickLook):
+    def __init__(self, data):
+        if 'error' not in data:
+            self.data = data
+        else:
+            self.data = None
+
+    @classmethod
+    def from_sdc(cls, start_utc: str, end_utc: str, ltc=False):
+        """ fetch light curve data from STIX data center
+
+        Args:
+            start_utc: str
+                data start UTC
+            end_utc: str
+                data end UTC
+            ltc: bool
+                Light time correction flag. Do light time correction if it is True
+
+
+        Returns:
+            lc: python object
+                Lightcurve object
+
+        """
+        data = jreq.fetch_light_curves(start_utc, end_utc, ltc)
+        if 'light_curves' in data:
+            # correct key name
+            data['counts'] = data['light_curves']
+            del data['light_curves']
+        return cls(data)
+
+    def __getattr__(self, name):
+        if name == 'data':
+            return self.data
+
+    def get_data(self):
+        """ get light curve data
+        Returns:
+            data: dict
+                light curve data
+
+        """
+        return self.data
+
+    def peek(self, ax=None, legend_loc='upper right'):
+        """
+        Plot light curves
+        Args:
+            ltc: light time correction flag. The default value is False. Do light time correction if ltc=True
+        Returns
+            ax: matplotlib axs
+
+        """
+        if not self.data:
+            ax.text(0.5, 0.5, 'LC not available!')
+            return ax
+
+        if not ax:
+            _, ax = plt.subplots()
+        dt = [
+            datetime.datetime.utcfromtimestamp(t)
+            for t in self.data['unix_time']
+        ]
+        for i in range(5):
+            ax.plot(dt,
+                    self.data['counts'][str(i)],
+                    label=self.data['energy_bins']['names'][i])
+        dlt = self.data['DELTA_LIGHT_TIME']
+        light_time_corrected = self.data['IS_LIGHT_TIME_CORRECTED']
+
+        xlabel = f'UTC + {dlt:.2f} (4 sec time bins)' if light_time_corrected else 'UTC (4 sec time bins)'
+        ax.set_xlabel(xlabel)
+        ax.set_ylabel('Counts')
+        ax.legend(loc=legend_loc)
+        ax.set_yscale('log')
+        return ax
+
+

Ancestors

+ +

Static methods

+
+
+def from_sdc(start_utc: str, end_utc: str, ltc=False) +
+
+

fetch light curve data from STIX data center

+

Args

+
+
start_utc
+
str +data start UTC
+
end_utc
+
str +data end UTC
+
ltc
+
bool +Light time correction flag. Do light time correction if it is True
+
+

Returns

+
+
lc
+
python object +Lightcurve object
+
+
+ +Expand source code + +
@classmethod
+def from_sdc(cls, start_utc: str, end_utc: str, ltc=False):
+    """ fetch light curve data from STIX data center
+
+    Args:
+        start_utc: str
+            data start UTC
+        end_utc: str
+            data end UTC
+        ltc: bool
+            Light time correction flag. Do light time correction if it is True
+
+
+    Returns:
+        lc: python object
+            Lightcurve object
+
+    """
+    data = jreq.fetch_light_curves(start_utc, end_utc, ltc)
+    if 'light_curves' in data:
+        # correct key name
+        data['counts'] = data['light_curves']
+        del data['light_curves']
+    return cls(data)
+
+
+
+

Methods

+
+
+def get_data(self) +
+
+

get light curve data

+

Returns

+
+
data
+
dict +light curve data
+
+
+ +Expand source code + +
def get_data(self):
+    """ get light curve data
+    Returns:
+        data: dict
+            light curve data
+
+    """
+    return self.data
+
+
+
+def peek(self, ax=None, legend_loc='upper right') +
+
+

Plot light curves

+

Args

+
+
ltc
+
light time correction flag. The default value is False. Do light time correction if ltc=True
+
+

Returns +ax: matplotlib axs

+
+ +Expand source code + +
def peek(self, ax=None, legend_loc='upper right'):
+    """
+    Plot light curves
+    Args:
+        ltc: light time correction flag. The default value is False. Do light time correction if ltc=True
+    Returns
+        ax: matplotlib axs
+
+    """
+    if not self.data:
+        ax.text(0.5, 0.5, 'LC not available!')
+        return ax
+
+    if not ax:
+        _, ax = plt.subplots()
+    dt = [
+        datetime.datetime.utcfromtimestamp(t)
+        for t in self.data['unix_time']
+    ]
+    for i in range(5):
+        ax.plot(dt,
+                self.data['counts'][str(i)],
+                label=self.data['energy_bins']['names'][i])
+    dlt = self.data['DELTA_LIGHT_TIME']
+    light_time_corrected = self.data['IS_LIGHT_TIME_CORRECTED']
+
+    xlabel = f'UTC + {dlt:.2f} (4 sec time bins)' if light_time_corrected else 'UTC (4 sec time bins)'
+    ax.set_xlabel(xlabel)
+    ax.set_ylabel('Counts')
+    ax.legend(loc=legend_loc)
+    ax.set_yscale('log')
+    return ax
+
+
+
+

Inherited members

+ +
+
+class QuickLook +
+
+

Base object

+
+ +Expand source code + +
class QuickLook(sio.IO):
+    def __init__(self):
+        pass
+
+    # def save_fits(self,fname):
+    #    self.data.writeto(fname)
+
+

Ancestors

+ +

Subclasses

+ +

Inherited members

+ +
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/science.html b/docs/stixdcpy/science.html new file mode 100644 index 0000000..cfc2150 --- /dev/null +++ b/docs/stixdcpy/science.html @@ -0,0 +1,1577 @@ + + + + + + +stixdcpy.science API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.science

+
+
+

This module provides APIs to retrieve Quick-look data from STIX data center , and provides tools to display the data +Author: Hualin Xiao (hualin.xiao@fhnw.ch) +Date: Sep. 1, 2021

+
+ +Expand source code + +
#!/usr/bin/python
+"""
+    This module provides APIs to retrieve Quick-look data from STIX data center , and provides tools to display the data
+    Author: Hualin Xiao (hualin.xiao@fhnw.ch)
+    Date: Sep. 1, 2021
+"""
+import datetime
+import numpy as np
+from astropy.io import fits
+from matplotlib import pyplot as plt
+from stixdcpy import time as sdt
+from stixdcpy.logger import logger
+from stixdcpy import io as sio, net
+from stixdcpy.net import FitsQuery as freq
+from stixdcpy import instrument as inst
+from pathlib import PurePath
+
+FPGA_TAU=10.1e-6
+ASIC_TAU=2.63e-6
+
+
+class ScienceData(sio.IO):
+    """
+      Retrieve science data from stix data center or load fits file from local storage
+
+    """
+    def __init__(self, request_id=None, fname=None):
+        self.fname = fname
+        self.data_type=None
+        if not fname:
+            raise Exception("FITS filename not specified")
+        self.request_id = request_id
+        self.time_shift_applied=0
+        self.hdul = fits.open(fname)
+        self.energies=[]
+        #self.read_data()
+    @property
+    def url(self):
+        req_id=self.request_id if not isinstance(self.request_id, list) else self.request_id[0]
+        link=f'{net.HOST}/view/list/bsd/uid/{req_id}'
+        return f'<a href="{link}">{link}</a>'
+
+    def read_fits(self, light_time_correction=True):
+        """
+            Read data  L1 compression level  FITS files
+            Parameters
+            ---------------------
+            light_time_correction: boolean
+                Correct light time difference
+        """
+
+        self.data = self.hdul['DATA'].data
+        self.T0_utc = self.hdul['PRIMARY'].header['DATE_BEG']
+        self.counts= self.data['counts']
+
+        self.light_time_del= self.hdul['PRIMARY'].header['EAR_TDEL']
+        self.light_time_corrected=light_time_correction
+
+        self.T0_unix = sdt.utc2unix(self.T0_utc)
+        self.triggers = self.data['triggers']
+        self.rcr = self.data['rcr']
+
+        self.timedel = self.data['timedel']
+        self.time = self.data['time']
+
+        if self.is_time_bin_shifted(self.T0_unix):
+            self.timedel = self.timedel[:-1]
+            self.time = self.time[1:]
+            logger.info('Shifted time bins have been corrected automatically!')
+            if self.data_type=='ScienceL1':
+                self.counts= self.counts[1:, :, :, :]
+                self.triggers = self.triggers[1:, :]
+                self.rcr = self.rcr[1:]
+            elif self.data_type=='Spectrogram':
+                self.counts= self.counts[1:, :]
+                self.triggers = self.triggers[1:]
+                #self.rcr = self.rcr[1:]
+
+        self.request_id = self.hdul['CONTROL'].data['request_id']
+        
+        self.time_shift_applied=0 if light_time_correction else self.light_time_del
+        self.datetime = [
+            sdt.unix2datetime(self.T0_unix + x + y * 0.5 + self.time_shift_applied)
+            for x, y in zip(self.time, self.timedel)
+        ]
+
+        self.duration = self.time[-1] - self.time[0] + (self.timedel[0] +
+                                                        self.timedel[-1]) / 2
+
+        self.energies = self.hdul['ENERGIES'].data
+
+        self.energy_bin_names = [
+            f'{a} - {b}'
+            for a, b in zip(self.energies['e_low'], self.energies['e_high'])
+        ]
+        self.energy_bin_mask = self.hdul["CONTROL"].data["energy_bin_mask"]
+
+        ebin_nz_idx =self.energy_bin_mask.nonzero()
+        self.max_ebin = np.max(ebin_nz_idx)  #indices of the non-zero elements
+        self.min_ebin = np.min(ebin_nz_idx)
+
+        self.ebins_mid = [
+            (a + b) / 2.
+            for a, b in zip(self.energies['e_low'], self.energies['e_high'])
+        ]
+        self.ebins_low, self.ebins_high = self.energies[
+            'e_low'], self.energies['e_high']
+
+        if self.data_type=='ScienceL1':
+            self.pixel_counts=self.counts
+            self.pixel_count_rates= self.pixel_counts/self.timedel[:,None,None, None]
+            self.trigger_rates = self.triggers / self.timedel[:, None] 
+        elif self.data_type=='Spectrogram':
+            self.count_rates= self.counts/self.timedel[:,None]
+            self.trigger_rates = self.triggers / self.timedel
+
+
+    def is_time_bin_shifted(self, unix_time):
+        """
+            Time bins are shifted in the data collected before 2021-12-09 due a bug in the flight software
+
+            Check if time bin is shifted in L1 data
+            Parameters
+                unix_time: float 
+            Returns
+                is_shifted: bool
+                    True if time bin is shifted else False
+        """
+
+        return (unix_time < sdt.utc2unix('2021-12-09T14:00:00'))
+
+    @classmethod
+    def from_sdc(cls, request_id):
+        '''
+        download science data file from stix data center
+        Parameters
+        ------
+        request_id :  int
+            bulk science data request unique ID; Unique IDs can be found on the science data web page  at stix data center
+
+
+        Returns
+        ------
+            science data class object
+        '''
+        request_id = request_id
+        fname = freq.fetch_bulk_science_by_request_id(request_id)
+        return cls(request_id, fname)
+
+    @classmethod
+    def from_fits(cls, filename):
+        """
+        factory class
+        Arguments
+        filename: str
+            FITS filename
+        """
+        request_id = None
+        return cls(request_id, filename)
+
+    def get_energy_range_slicer(self, elow, ehigh):
+        sel=[]
+        i=0
+        for a, b in zip(self.energies['e_low'], self.energies['e_high']):
+            if a>=elow  and b<=ehigh:
+                sel.append(i)
+            i+=1
+        return slice(min(sel),max(sel))
+
+
+
+    def rebin(self, ebins, min_tbin=0):
+        """
+         Energy rebin and time rebin
+         Arguments:
+         ebins: list or numpy array
+            energy bin range in units of keV
+         min_tbin: float
+            minimum time bin, shorter time bins are merged
+         Returns:
+            an object containing rebinned light curves
+        """
+        pass
+
+    def save(self, filename=None):
+        '''
+           Save data to a fits file
+           Parameters
+           filename : output fits filename
+           Returns
+           filename if success or error message
+        '''
+        if not isinstance(self.hdul, fits.hdu.hdulist.HDUList):
+            logger.error('The data object is a not a fits hdu object!')
+            return None
+        try:
+            if filename is None:
+                basename = self.hdul['PRIMARY'].header['FILENAME']
+                filename = PurePath(net.DOWNLOAD_PATH, basename)
+            self.hdul.writeto(filename)
+            return filename
+        except Exception as e:
+            logger.error(e)
+
+    def __getattr__(self, name):
+        if name == 'data':
+            return self.hdul
+        elif name == 'type':
+            return self.hdul.get('data_type', 'INVALID_TYPE')
+        elif name == 'filename':
+            return self.fname
+
+    def get_data(self):
+        return self.hdul
+
+
+class ScienceL1(ScienceData):
+    """
+    Tools to analyze L1 science data
+    """
+
+    def __init__(self, reqeust_id,fname):
+        print(reqeust_id, fname)
+        super().__init__(reqeust_id, fname)
+        self.data_type='ScienceL1'
+        self.pixel_count_rates=None
+        self.correct_pixel_count_rates=None
+        self.read_fits()
+        self.make_spectra()
+
+    def make_spectra(self, pixel_counts=None):
+        if pixel_counts is None:
+            pixel_counts=self.pixel_counts
+        self.spectrogram = np.sum(pixel_counts, axis=(1, 2))
+        self.count_rate_spectrogram = self.spectrogram / self.timedel[:, np.
+                                                                      newaxis]
+        self.spectrum = np.sum(pixel_counts, axis=(0, 1, 2))
+        self.mean_pixel_rate_spectra = np.sum(self.pixel_counts,
+                                              axis=0) / self.duration
+        self.mean_pixel_rate_spectra_err = np.sqrt(
+            self.mean_pixel_rate_spectra) / np.sqrt(self.duration)
+        #sum over all time bins and then divide them by the duration, counts per second
+
+    def solve_cfl(self, start_utc, end_utc, elow=0, eup=31, ax=None):
+        """calculate flare location using the online flare location solver.
+          
+        Args:
+            start_utc: str
+                ROI start time
+            end_utc: str
+                ROI end time
+            elow: int
+                ROI lower energy limit (science channel). 
+            eup: int
+                ROI upper energy limit (science channel). 
+        Returns:
+            cfl_loc: dict
+                containing coarse flare location as well as ephemeris and chisquare map
+
+        """
+        pass
+
+    def correct_live_time(self, clone=False):
+        """ Live time correction
+        Returns:
+          scienceL1 object
+        """
+
+        trig_tau = FPGA_TAU+ASIC_TAU
+        time_bins = self.time_bins[:, None]
+        photons_in = self.triggers/(time_bins-trig_tau*self.triggers)
+        #photon rate calculated using triggers 
+        cm= np.zeros((time_bins.size, 32))
+        time_bins = time_bins[:, :, None, None]
+        count_rates = self.pixel_counts/time_bins
+        for det in range(32):
+            trig_idx=inst.detector_id_to_trigger_index(det)
+
+            cm[:,det]= 1 + self.trigger_rates[:,trig_idx]*FPGA_TAU #live time per second 
+        self.correct_pixel_count_rates=count_rates*cm[:, :, None, None]/np.exp(-count_rates*ASIC_TAU)
+        return self
+
+    def peek(self,
+             plots=['spg', 'lc', 'spec', 'tbin', 'qllc'],
+             ax0=None,
+             ax1=None,
+             ax2=None,
+             ax3=None):
+        """
+            Create quick-look plots for the loaded science data
+        """
+        if not self.hdul:
+            logger.logger(f'Data not loaded. ')
+            return None
+        if isinstance(plots, str) and plots:
+            plots = plots.split(',')
+        if not self.data_loaded:
+            self.read_fits()
+            self.data_loaded = True
+
+        if 'spg' in plots:
+            if not ax0:
+                _, ax0 = plt.subplots()
+            X, Y = np.meshgrid(self.time,
+                               np.arange(self.min_ebin, self.max_ebin))
+            im = ax0.pcolormesh(
+                X, Y,
+                np.transpose(
+                    self.count_rate_spectrogram[:, self.min_ebin:self.max_ebin]
+                ))  #pixel summed energy spectrum
+            ax0.set_yticks(
+                self.energies['channel'][self.min_ebin:self.max_ebin:2])
+            ax0.set_yticklabels(
+                self.energy_bin_names[self.min_ebin:self.max_ebin:2])
+            fig = plt.gcf()
+            cbar = fig.colorbar(im, ax=ax0)
+            cbar.set_label('Counts')
+            ax0.set_title('Count rate spectrogram')
+            ax0.set_ylabel('Energy range(keV')
+            ax0.set_xlabel(f"T0 at {self.T0_utc} ")
+        if 'lc' in plots or 'qllc' in plots:
+            if not ax1:
+                _, ax1 = plt.subplots()
+            self.count_rate_spectrogram = self.spectrogram / self.timedel[:,
+                                                                          None]
+            if 'qllc' in plots:
+               ql_ebins=[(4, 10),(10 ,15 ),(15 ,25 ),(25 ,50), (50 ,84)]
+               labels=('4 - 10 keV','10 - 15 keV','15 - 25 keV','25 - 50 keV', '50 - 84 keV')
+               ql_sci_ebins=[self.get_energy_range_slicer(s[0],s[1]) for s in ql_ebins]
+               for ebin_slicer,label in zip(ql_sci_ebins, labels):
+                   ax1.plot(self.time,
+                        np.sum(self.count_rate_spectrogram[:, ebin_slicer], axis=1),label=label) 
+                   ax1.set_title(f'Detector summed count rates (L1 request #{self.request_id})')
+            else:
+                ax1.plot(
+                    self.time,
+                    self.count_rate_spectrogram[:, self.min_ebin:self.max_ebin])
+            #correct
+            ax1.set_ylabel('counts / sec')
+            #plt.legend(self.energy_bin_names, ncol=4)
+            ax1.set_yscale('log')
+            ax1.set_xlabel(f"seconds since {self.T0_utc} ")
+            plt.legend()
+        if 'spec' in plots:
+            if not ax2:
+                _, ax2 = plt.subplots()
+            ax2.plot(self.ebins_low, self.spectrum, drawstyle='steps-post')
+            #ax.set_xticks(self.data[3].data['channel'])
+            ax2.set_xscale('log')
+            ax2.set_yscale('log')
+            ax2.set_xlabel('Energy (keV)')
+            ax2.set_ylabel('Counts')
+        if 'tbin' in plots:
+            if not ax3:
+                _, ax3 = plt.subplots()
+            ax3.plot(self.time, self.timedel)
+            ax3.set_xlabel(f"T0 at {self.T0_utc} ")
+            ax3.set_ylabel('Integration time (sec)')
+            plt.suptitle(f'L1 request #{self.request_id}')
+
+        #plt.tight_layout()
+        return ax0, ax1, ax2, ax3
+
+
+class Spectrogram(ScienceData):
+
+
+    def __init__(self, reqeust_id,fname):
+        super().__init__(reqeust_id, fname)
+        self.data_type='Spectrogram'
+
+        self.read_fits()
+
+        self.spectrum = np.sum(self.counts, axis=0)
+
+    def peek(self, ax0=None, ax1=None, ax2=None, ax3=None):
+        """
+            preivew Science data
+        Arguments:
+        ax0: matplotlib axe 
+        ax0: matplotlib axe 
+        """
+        if not self.hdul:
+            print(f'Data not loaded. ')
+            return None
+
+        #((ax0, ax1), (ax2, ax3))=axs
+        if not any([ax0, ax1, ax2, ax3]):
+            _, ((ax0, ax1), (ax2, ax3)) = plt.subplots(2, 2, figsize=(8, 6))
+
+        if ax0:
+            X, Y = np.meshgrid(self.time,
+                               self.hdul['ENERGIES'].data['channel'])
+            im = ax0.pcolormesh(X, Y, np.transpose(
+                self.counts))  #pixel summed energy spectrum
+            ax0.set_yticks(self.hdul['ENERGIES'].data['channel'][::2])
+            ax0.set_yticklabels(self.energy_bin_names[::2])
+            fig = plt.gcf()
+            cbar = fig.colorbar(im, ax=ax0)
+            cbar.set_label('Counts')
+            ax0.set_title('Spectrogram')
+            ax0.set_ylabel('Energy range(keV')
+            ax0.set_xlabel(f"Seconds since {self.T0}s ")
+        if ax1:
+            #convert to 2d
+            ax1.plot(self.time, self.count_rates)
+            ax1.set_yscale('log')
+            ax1.set_ylabel('Counts / sec')
+            ax1.set_xlabel(f"Seconds since {self.T0}s ")
+        if ax2:
+            ax2.plot(self.ebins_low, self.spectrum, drawstyle='steps-post')
+            ax2.set_xscale('log')
+            ax2.set_yscale('log')
+            ax2.set_xlabel('Energy (keV)')
+            ax2.set_ylabel('Counts')
+        if ax3:
+            ax3.plot(self.time, self.timedel)
+            ax3.set_xlabel(f"Seconds since {self.T0}s ")
+            ax3.set_ylabel('Integration time (sec)')
+        plt.suptitle(f'L4 request #{self.request_id}')
+        plt.tight_layout()
+        return fig, ((ax0, ax1), (ax2, ax3))
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class ScienceData +(request_id=None, fname=None) +
+
+

Retrieve science data from stix data center or load fits file from local storage

+
+ +Expand source code + +
class ScienceData(sio.IO):
+    """
+      Retrieve science data from stix data center or load fits file from local storage
+
+    """
+    def __init__(self, request_id=None, fname=None):
+        self.fname = fname
+        self.data_type=None
+        if not fname:
+            raise Exception("FITS filename not specified")
+        self.request_id = request_id
+        self.time_shift_applied=0
+        self.hdul = fits.open(fname)
+        self.energies=[]
+        #self.read_data()
+    @property
+    def url(self):
+        req_id=self.request_id if not isinstance(self.request_id, list) else self.request_id[0]
+        link=f'{net.HOST}/view/list/bsd/uid/{req_id}'
+        return f'<a href="{link}">{link}</a>'
+
+    def read_fits(self, light_time_correction=True):
+        """
+            Read data  L1 compression level  FITS files
+            Parameters
+            ---------------------
+            light_time_correction: boolean
+                Correct light time difference
+        """
+
+        self.data = self.hdul['DATA'].data
+        self.T0_utc = self.hdul['PRIMARY'].header['DATE_BEG']
+        self.counts= self.data['counts']
+
+        self.light_time_del= self.hdul['PRIMARY'].header['EAR_TDEL']
+        self.light_time_corrected=light_time_correction
+
+        self.T0_unix = sdt.utc2unix(self.T0_utc)
+        self.triggers = self.data['triggers']
+        self.rcr = self.data['rcr']
+
+        self.timedel = self.data['timedel']
+        self.time = self.data['time']
+
+        if self.is_time_bin_shifted(self.T0_unix):
+            self.timedel = self.timedel[:-1]
+            self.time = self.time[1:]
+            logger.info('Shifted time bins have been corrected automatically!')
+            if self.data_type=='ScienceL1':
+                self.counts= self.counts[1:, :, :, :]
+                self.triggers = self.triggers[1:, :]
+                self.rcr = self.rcr[1:]
+            elif self.data_type=='Spectrogram':
+                self.counts= self.counts[1:, :]
+                self.triggers = self.triggers[1:]
+                #self.rcr = self.rcr[1:]
+
+        self.request_id = self.hdul['CONTROL'].data['request_id']
+        
+        self.time_shift_applied=0 if light_time_correction else self.light_time_del
+        self.datetime = [
+            sdt.unix2datetime(self.T0_unix + x + y * 0.5 + self.time_shift_applied)
+            for x, y in zip(self.time, self.timedel)
+        ]
+
+        self.duration = self.time[-1] - self.time[0] + (self.timedel[0] +
+                                                        self.timedel[-1]) / 2
+
+        self.energies = self.hdul['ENERGIES'].data
+
+        self.energy_bin_names = [
+            f'{a} - {b}'
+            for a, b in zip(self.energies['e_low'], self.energies['e_high'])
+        ]
+        self.energy_bin_mask = self.hdul["CONTROL"].data["energy_bin_mask"]
+
+        ebin_nz_idx =self.energy_bin_mask.nonzero()
+        self.max_ebin = np.max(ebin_nz_idx)  #indices of the non-zero elements
+        self.min_ebin = np.min(ebin_nz_idx)
+
+        self.ebins_mid = [
+            (a + b) / 2.
+            for a, b in zip(self.energies['e_low'], self.energies['e_high'])
+        ]
+        self.ebins_low, self.ebins_high = self.energies[
+            'e_low'], self.energies['e_high']
+
+        if self.data_type=='ScienceL1':
+            self.pixel_counts=self.counts
+            self.pixel_count_rates= self.pixel_counts/self.timedel[:,None,None, None]
+            self.trigger_rates = self.triggers / self.timedel[:, None] 
+        elif self.data_type=='Spectrogram':
+            self.count_rates= self.counts/self.timedel[:,None]
+            self.trigger_rates = self.triggers / self.timedel
+
+
+    def is_time_bin_shifted(self, unix_time):
+        """
+            Time bins are shifted in the data collected before 2021-12-09 due a bug in the flight software
+
+            Check if time bin is shifted in L1 data
+            Parameters
+                unix_time: float 
+            Returns
+                is_shifted: bool
+                    True if time bin is shifted else False
+        """
+
+        return (unix_time < sdt.utc2unix('2021-12-09T14:00:00'))
+
+    @classmethod
+    def from_sdc(cls, request_id):
+        '''
+        download science data file from stix data center
+        Parameters
+        ------
+        request_id :  int
+            bulk science data request unique ID; Unique IDs can be found on the science data web page  at stix data center
+
+
+        Returns
+        ------
+            science data class object
+        '''
+        request_id = request_id
+        fname = freq.fetch_bulk_science_by_request_id(request_id)
+        return cls(request_id, fname)
+
+    @classmethod
+    def from_fits(cls, filename):
+        """
+        factory class
+        Arguments
+        filename: str
+            FITS filename
+        """
+        request_id = None
+        return cls(request_id, filename)
+
+    def get_energy_range_slicer(self, elow, ehigh):
+        sel=[]
+        i=0
+        for a, b in zip(self.energies['e_low'], self.energies['e_high']):
+            if a>=elow  and b<=ehigh:
+                sel.append(i)
+            i+=1
+        return slice(min(sel),max(sel))
+
+
+
+    def rebin(self, ebins, min_tbin=0):
+        """
+         Energy rebin and time rebin
+         Arguments:
+         ebins: list or numpy array
+            energy bin range in units of keV
+         min_tbin: float
+            minimum time bin, shorter time bins are merged
+         Returns:
+            an object containing rebinned light curves
+        """
+        pass
+
+    def save(self, filename=None):
+        '''
+           Save data to a fits file
+           Parameters
+           filename : output fits filename
+           Returns
+           filename if success or error message
+        '''
+        if not isinstance(self.hdul, fits.hdu.hdulist.HDUList):
+            logger.error('The data object is a not a fits hdu object!')
+            return None
+        try:
+            if filename is None:
+                basename = self.hdul['PRIMARY'].header['FILENAME']
+                filename = PurePath(net.DOWNLOAD_PATH, basename)
+            self.hdul.writeto(filename)
+            return filename
+        except Exception as e:
+            logger.error(e)
+
+    def __getattr__(self, name):
+        if name == 'data':
+            return self.hdul
+        elif name == 'type':
+            return self.hdul.get('data_type', 'INVALID_TYPE')
+        elif name == 'filename':
+            return self.fname
+
+    def get_data(self):
+        return self.hdul
+
+

Ancestors

+ +

Subclasses

+ +

Static methods

+
+
+def from_fits(filename) +
+
+

factory class +Arguments +filename: str +FITS filename

+
+ +Expand source code + +
@classmethod
+def from_fits(cls, filename):
+    """
+    factory class
+    Arguments
+    filename: str
+        FITS filename
+    """
+    request_id = None
+    return cls(request_id, filename)
+
+
+
+def from_sdc(request_id) +
+
+

download science data file from stix data center +Parameters

+
+
+
request_id :  int
+
bulk science data request unique ID; Unique IDs can be found on the science data web page +at stix data center
+
+

Returns

+
science data class object
+
+
+ +Expand source code + +
@classmethod
+def from_sdc(cls, request_id):
+    '''
+    download science data file from stix data center
+    Parameters
+    ------
+    request_id :  int
+        bulk science data request unique ID; Unique IDs can be found on the science data web page  at stix data center
+
+
+    Returns
+    ------
+        science data class object
+    '''
+    request_id = request_id
+    fname = freq.fetch_bulk_science_by_request_id(request_id)
+    return cls(request_id, fname)
+
+
+
+

Instance variables

+
+
var url
+
+
+
+ +Expand source code + +
@property
+def url(self):
+    req_id=self.request_id if not isinstance(self.request_id, list) else self.request_id[0]
+    link=f'{net.HOST}/view/list/bsd/uid/{req_id}'
+    return f'<a href="{link}">{link}</a>'
+
+
+
+

Methods

+
+
+def get_data(self) +
+
+
+
+ +Expand source code + +
def get_data(self):
+    return self.hdul
+
+
+
+def get_energy_range_slicer(self, elow, ehigh) +
+
+
+
+ +Expand source code + +
def get_energy_range_slicer(self, elow, ehigh):
+    sel=[]
+    i=0
+    for a, b in zip(self.energies['e_low'], self.energies['e_high']):
+        if a>=elow  and b<=ehigh:
+            sel.append(i)
+        i+=1
+    return slice(min(sel),max(sel))
+
+
+
+def is_time_bin_shifted(self, unix_time) +
+
+

Time bins are shifted in the data collected before 2021-12-09 due a bug in the flight software

+

Check if time bin is shifted in L1 data +Parameters +unix_time: float +Returns +is_shifted: bool +True if time bin is shifted else False

+
+ +Expand source code + +
def is_time_bin_shifted(self, unix_time):
+    """
+        Time bins are shifted in the data collected before 2021-12-09 due a bug in the flight software
+
+        Check if time bin is shifted in L1 data
+        Parameters
+            unix_time: float 
+        Returns
+            is_shifted: bool
+                True if time bin is shifted else False
+    """
+
+    return (unix_time < sdt.utc2unix('2021-12-09T14:00:00'))
+
+
+
+def read_fits(self, light_time_correction=True) +
+
+

Read data +L1 compression level +FITS files +Parameters

+
+
+
light_time_correction : boolean
+
Correct light time difference
+
+
+ +Expand source code + +
def read_fits(self, light_time_correction=True):
+    """
+        Read data  L1 compression level  FITS files
+        Parameters
+        ---------------------
+        light_time_correction: boolean
+            Correct light time difference
+    """
+
+    self.data = self.hdul['DATA'].data
+    self.T0_utc = self.hdul['PRIMARY'].header['DATE_BEG']
+    self.counts= self.data['counts']
+
+    self.light_time_del= self.hdul['PRIMARY'].header['EAR_TDEL']
+    self.light_time_corrected=light_time_correction
+
+    self.T0_unix = sdt.utc2unix(self.T0_utc)
+    self.triggers = self.data['triggers']
+    self.rcr = self.data['rcr']
+
+    self.timedel = self.data['timedel']
+    self.time = self.data['time']
+
+    if self.is_time_bin_shifted(self.T0_unix):
+        self.timedel = self.timedel[:-1]
+        self.time = self.time[1:]
+        logger.info('Shifted time bins have been corrected automatically!')
+        if self.data_type=='ScienceL1':
+            self.counts= self.counts[1:, :, :, :]
+            self.triggers = self.triggers[1:, :]
+            self.rcr = self.rcr[1:]
+        elif self.data_type=='Spectrogram':
+            self.counts= self.counts[1:, :]
+            self.triggers = self.triggers[1:]
+            #self.rcr = self.rcr[1:]
+
+    self.request_id = self.hdul['CONTROL'].data['request_id']
+    
+    self.time_shift_applied=0 if light_time_correction else self.light_time_del
+    self.datetime = [
+        sdt.unix2datetime(self.T0_unix + x + y * 0.5 + self.time_shift_applied)
+        for x, y in zip(self.time, self.timedel)
+    ]
+
+    self.duration = self.time[-1] - self.time[0] + (self.timedel[0] +
+                                                    self.timedel[-1]) / 2
+
+    self.energies = self.hdul['ENERGIES'].data
+
+    self.energy_bin_names = [
+        f'{a} - {b}'
+        for a, b in zip(self.energies['e_low'], self.energies['e_high'])
+    ]
+    self.energy_bin_mask = self.hdul["CONTROL"].data["energy_bin_mask"]
+
+    ebin_nz_idx =self.energy_bin_mask.nonzero()
+    self.max_ebin = np.max(ebin_nz_idx)  #indices of the non-zero elements
+    self.min_ebin = np.min(ebin_nz_idx)
+
+    self.ebins_mid = [
+        (a + b) / 2.
+        for a, b in zip(self.energies['e_low'], self.energies['e_high'])
+    ]
+    self.ebins_low, self.ebins_high = self.energies[
+        'e_low'], self.energies['e_high']
+
+    if self.data_type=='ScienceL1':
+        self.pixel_counts=self.counts
+        self.pixel_count_rates= self.pixel_counts/self.timedel[:,None,None, None]
+        self.trigger_rates = self.triggers / self.timedel[:, None] 
+    elif self.data_type=='Spectrogram':
+        self.count_rates= self.counts/self.timedel[:,None]
+        self.trigger_rates = self.triggers / self.timedel
+
+
+
+def rebin(self, ebins, min_tbin=0) +
+
+

Energy rebin and time rebin +Arguments: +ebins: list or numpy array +energy bin range in units of keV +min_tbin: float +minimum time bin, shorter time bins are merged

+

Returns

+

an object containing rebinned light curves

+
+ +Expand source code + +
def rebin(self, ebins, min_tbin=0):
+    """
+     Energy rebin and time rebin
+     Arguments:
+     ebins: list or numpy array
+        energy bin range in units of keV
+     min_tbin: float
+        minimum time bin, shorter time bins are merged
+     Returns:
+        an object containing rebinned light curves
+    """
+    pass
+
+
+
+def save(self, filename=None) +
+
+

Save data to a fits file +Parameters +filename : output fits filename +Returns +filename if success or error message

+
+ +Expand source code + +
def save(self, filename=None):
+    '''
+       Save data to a fits file
+       Parameters
+       filename : output fits filename
+       Returns
+       filename if success or error message
+    '''
+    if not isinstance(self.hdul, fits.hdu.hdulist.HDUList):
+        logger.error('The data object is a not a fits hdu object!')
+        return None
+    try:
+        if filename is None:
+            basename = self.hdul['PRIMARY'].header['FILENAME']
+            filename = PurePath(net.DOWNLOAD_PATH, basename)
+        self.hdul.writeto(filename)
+        return filename
+    except Exception as e:
+        logger.error(e)
+
+
+
+

Inherited members

+ +
+
+class ScienceL1 +(reqeust_id, fname) +
+
+

Tools to analyze L1 science data

+
+ +Expand source code + +
class ScienceL1(ScienceData):
+    """
+    Tools to analyze L1 science data
+    """
+
+    def __init__(self, reqeust_id,fname):
+        print(reqeust_id, fname)
+        super().__init__(reqeust_id, fname)
+        self.data_type='ScienceL1'
+        self.pixel_count_rates=None
+        self.correct_pixel_count_rates=None
+        self.read_fits()
+        self.make_spectra()
+
+    def make_spectra(self, pixel_counts=None):
+        if pixel_counts is None:
+            pixel_counts=self.pixel_counts
+        self.spectrogram = np.sum(pixel_counts, axis=(1, 2))
+        self.count_rate_spectrogram = self.spectrogram / self.timedel[:, np.
+                                                                      newaxis]
+        self.spectrum = np.sum(pixel_counts, axis=(0, 1, 2))
+        self.mean_pixel_rate_spectra = np.sum(self.pixel_counts,
+                                              axis=0) / self.duration
+        self.mean_pixel_rate_spectra_err = np.sqrt(
+            self.mean_pixel_rate_spectra) / np.sqrt(self.duration)
+        #sum over all time bins and then divide them by the duration, counts per second
+
+    def solve_cfl(self, start_utc, end_utc, elow=0, eup=31, ax=None):
+        """calculate flare location using the online flare location solver.
+          
+        Args:
+            start_utc: str
+                ROI start time
+            end_utc: str
+                ROI end time
+            elow: int
+                ROI lower energy limit (science channel). 
+            eup: int
+                ROI upper energy limit (science channel). 
+        Returns:
+            cfl_loc: dict
+                containing coarse flare location as well as ephemeris and chisquare map
+
+        """
+        pass
+
+    def correct_live_time(self, clone=False):
+        """ Live time correction
+        Returns:
+          scienceL1 object
+        """
+
+        trig_tau = FPGA_TAU+ASIC_TAU
+        time_bins = self.time_bins[:, None]
+        photons_in = self.triggers/(time_bins-trig_tau*self.triggers)
+        #photon rate calculated using triggers 
+        cm= np.zeros((time_bins.size, 32))
+        time_bins = time_bins[:, :, None, None]
+        count_rates = self.pixel_counts/time_bins
+        for det in range(32):
+            trig_idx=inst.detector_id_to_trigger_index(det)
+
+            cm[:,det]= 1 + self.trigger_rates[:,trig_idx]*FPGA_TAU #live time per second 
+        self.correct_pixel_count_rates=count_rates*cm[:, :, None, None]/np.exp(-count_rates*ASIC_TAU)
+        return self
+
+    def peek(self,
+             plots=['spg', 'lc', 'spec', 'tbin', 'qllc'],
+             ax0=None,
+             ax1=None,
+             ax2=None,
+             ax3=None):
+        """
+            Create quick-look plots for the loaded science data
+        """
+        if not self.hdul:
+            logger.logger(f'Data not loaded. ')
+            return None
+        if isinstance(plots, str) and plots:
+            plots = plots.split(',')
+        if not self.data_loaded:
+            self.read_fits()
+            self.data_loaded = True
+
+        if 'spg' in plots:
+            if not ax0:
+                _, ax0 = plt.subplots()
+            X, Y = np.meshgrid(self.time,
+                               np.arange(self.min_ebin, self.max_ebin))
+            im = ax0.pcolormesh(
+                X, Y,
+                np.transpose(
+                    self.count_rate_spectrogram[:, self.min_ebin:self.max_ebin]
+                ))  #pixel summed energy spectrum
+            ax0.set_yticks(
+                self.energies['channel'][self.min_ebin:self.max_ebin:2])
+            ax0.set_yticklabels(
+                self.energy_bin_names[self.min_ebin:self.max_ebin:2])
+            fig = plt.gcf()
+            cbar = fig.colorbar(im, ax=ax0)
+            cbar.set_label('Counts')
+            ax0.set_title('Count rate spectrogram')
+            ax0.set_ylabel('Energy range(keV')
+            ax0.set_xlabel(f"T0 at {self.T0_utc} ")
+        if 'lc' in plots or 'qllc' in plots:
+            if not ax1:
+                _, ax1 = plt.subplots()
+            self.count_rate_spectrogram = self.spectrogram / self.timedel[:,
+                                                                          None]
+            if 'qllc' in plots:
+               ql_ebins=[(4, 10),(10 ,15 ),(15 ,25 ),(25 ,50), (50 ,84)]
+               labels=('4 - 10 keV','10 - 15 keV','15 - 25 keV','25 - 50 keV', '50 - 84 keV')
+               ql_sci_ebins=[self.get_energy_range_slicer(s[0],s[1]) for s in ql_ebins]
+               for ebin_slicer,label in zip(ql_sci_ebins, labels):
+                   ax1.plot(self.time,
+                        np.sum(self.count_rate_spectrogram[:, ebin_slicer], axis=1),label=label) 
+                   ax1.set_title(f'Detector summed count rates (L1 request #{self.request_id})')
+            else:
+                ax1.plot(
+                    self.time,
+                    self.count_rate_spectrogram[:, self.min_ebin:self.max_ebin])
+            #correct
+            ax1.set_ylabel('counts / sec')
+            #plt.legend(self.energy_bin_names, ncol=4)
+            ax1.set_yscale('log')
+            ax1.set_xlabel(f"seconds since {self.T0_utc} ")
+            plt.legend()
+        if 'spec' in plots:
+            if not ax2:
+                _, ax2 = plt.subplots()
+            ax2.plot(self.ebins_low, self.spectrum, drawstyle='steps-post')
+            #ax.set_xticks(self.data[3].data['channel'])
+            ax2.set_xscale('log')
+            ax2.set_yscale('log')
+            ax2.set_xlabel('Energy (keV)')
+            ax2.set_ylabel('Counts')
+        if 'tbin' in plots:
+            if not ax3:
+                _, ax3 = plt.subplots()
+            ax3.plot(self.time, self.timedel)
+            ax3.set_xlabel(f"T0 at {self.T0_utc} ")
+            ax3.set_ylabel('Integration time (sec)')
+            plt.suptitle(f'L1 request #{self.request_id}')
+
+        #plt.tight_layout()
+        return ax0, ax1, ax2, ax3
+
+

Ancestors

+ +

Methods

+
+
+def correct_live_time(self, clone=False) +
+
+

Live time correction

+

Returns

+

scienceL1 object

+
+ +Expand source code + +
def correct_live_time(self, clone=False):
+    """ Live time correction
+    Returns:
+      scienceL1 object
+    """
+
+    trig_tau = FPGA_TAU+ASIC_TAU
+    time_bins = self.time_bins[:, None]
+    photons_in = self.triggers/(time_bins-trig_tau*self.triggers)
+    #photon rate calculated using triggers 
+    cm= np.zeros((time_bins.size, 32))
+    time_bins = time_bins[:, :, None, None]
+    count_rates = self.pixel_counts/time_bins
+    for det in range(32):
+        trig_idx=inst.detector_id_to_trigger_index(det)
+
+        cm[:,det]= 1 + self.trigger_rates[:,trig_idx]*FPGA_TAU #live time per second 
+    self.correct_pixel_count_rates=count_rates*cm[:, :, None, None]/np.exp(-count_rates*ASIC_TAU)
+    return self
+
+
+
+def make_spectra(self, pixel_counts=None) +
+
+
+
+ +Expand source code + +
def make_spectra(self, pixel_counts=None):
+    if pixel_counts is None:
+        pixel_counts=self.pixel_counts
+    self.spectrogram = np.sum(pixel_counts, axis=(1, 2))
+    self.count_rate_spectrogram = self.spectrogram / self.timedel[:, np.
+                                                                  newaxis]
+    self.spectrum = np.sum(pixel_counts, axis=(0, 1, 2))
+    self.mean_pixel_rate_spectra = np.sum(self.pixel_counts,
+                                          axis=0) / self.duration
+    self.mean_pixel_rate_spectra_err = np.sqrt(
+        self.mean_pixel_rate_spectra) / np.sqrt(self.duration)
+    #sum over all time bins and then divide them by the duration, counts per second
+
+
+
+def peek(self, plots=['spg', 'lc', 'spec', 'tbin', 'qllc'], ax0=None, ax1=None, ax2=None, ax3=None) +
+
+

Create quick-look plots for the loaded science data

+
+ +Expand source code + +
def peek(self,
+         plots=['spg', 'lc', 'spec', 'tbin', 'qllc'],
+         ax0=None,
+         ax1=None,
+         ax2=None,
+         ax3=None):
+    """
+        Create quick-look plots for the loaded science data
+    """
+    if not self.hdul:
+        logger.logger(f'Data not loaded. ')
+        return None
+    if isinstance(plots, str) and plots:
+        plots = plots.split(',')
+    if not self.data_loaded:
+        self.read_fits()
+        self.data_loaded = True
+
+    if 'spg' in plots:
+        if not ax0:
+            _, ax0 = plt.subplots()
+        X, Y = np.meshgrid(self.time,
+                           np.arange(self.min_ebin, self.max_ebin))
+        im = ax0.pcolormesh(
+            X, Y,
+            np.transpose(
+                self.count_rate_spectrogram[:, self.min_ebin:self.max_ebin]
+            ))  #pixel summed energy spectrum
+        ax0.set_yticks(
+            self.energies['channel'][self.min_ebin:self.max_ebin:2])
+        ax0.set_yticklabels(
+            self.energy_bin_names[self.min_ebin:self.max_ebin:2])
+        fig = plt.gcf()
+        cbar = fig.colorbar(im, ax=ax0)
+        cbar.set_label('Counts')
+        ax0.set_title('Count rate spectrogram')
+        ax0.set_ylabel('Energy range(keV')
+        ax0.set_xlabel(f"T0 at {self.T0_utc} ")
+    if 'lc' in plots or 'qllc' in plots:
+        if not ax1:
+            _, ax1 = plt.subplots()
+        self.count_rate_spectrogram = self.spectrogram / self.timedel[:,
+                                                                      None]
+        if 'qllc' in plots:
+           ql_ebins=[(4, 10),(10 ,15 ),(15 ,25 ),(25 ,50), (50 ,84)]
+           labels=('4 - 10 keV','10 - 15 keV','15 - 25 keV','25 - 50 keV', '50 - 84 keV')
+           ql_sci_ebins=[self.get_energy_range_slicer(s[0],s[1]) for s in ql_ebins]
+           for ebin_slicer,label in zip(ql_sci_ebins, labels):
+               ax1.plot(self.time,
+                    np.sum(self.count_rate_spectrogram[:, ebin_slicer], axis=1),label=label) 
+               ax1.set_title(f'Detector summed count rates (L1 request #{self.request_id})')
+        else:
+            ax1.plot(
+                self.time,
+                self.count_rate_spectrogram[:, self.min_ebin:self.max_ebin])
+        #correct
+        ax1.set_ylabel('counts / sec')
+        #plt.legend(self.energy_bin_names, ncol=4)
+        ax1.set_yscale('log')
+        ax1.set_xlabel(f"seconds since {self.T0_utc} ")
+        plt.legend()
+    if 'spec' in plots:
+        if not ax2:
+            _, ax2 = plt.subplots()
+        ax2.plot(self.ebins_low, self.spectrum, drawstyle='steps-post')
+        #ax.set_xticks(self.data[3].data['channel'])
+        ax2.set_xscale('log')
+        ax2.set_yscale('log')
+        ax2.set_xlabel('Energy (keV)')
+        ax2.set_ylabel('Counts')
+    if 'tbin' in plots:
+        if not ax3:
+            _, ax3 = plt.subplots()
+        ax3.plot(self.time, self.timedel)
+        ax3.set_xlabel(f"T0 at {self.T0_utc} ")
+        ax3.set_ylabel('Integration time (sec)')
+        plt.suptitle(f'L1 request #{self.request_id}')
+
+    #plt.tight_layout()
+    return ax0, ax1, ax2, ax3
+
+
+
+def solve_cfl(self, start_utc, end_utc, elow=0, eup=31, ax=None) +
+
+

calculate flare location using the online flare location solver.

+

Args

+
+
start_utc
+
str +ROI start time
+
end_utc
+
str +ROI end time
+
elow
+
int +ROI lower energy limit (science channel).
+
eup
+
int +ROI upper energy limit (science channel).
+
+

Returns

+
+
cfl_loc
+
dict +containing coarse flare location as well as ephemeris and chisquare map
+
+
+ +Expand source code + +
def solve_cfl(self, start_utc, end_utc, elow=0, eup=31, ax=None):
+    """calculate flare location using the online flare location solver.
+      
+    Args:
+        start_utc: str
+            ROI start time
+        end_utc: str
+            ROI end time
+        elow: int
+            ROI lower energy limit (science channel). 
+        eup: int
+            ROI upper energy limit (science channel). 
+    Returns:
+        cfl_loc: dict
+            containing coarse flare location as well as ephemeris and chisquare map
+
+    """
+    pass
+
+
+
+

Inherited members

+ +
+
+class Spectrogram +(reqeust_id, fname) +
+
+

Retrieve science data from stix data center or load fits file from local storage

+
+ +Expand source code + +
class Spectrogram(ScienceData):
+
+
+    def __init__(self, reqeust_id,fname):
+        super().__init__(reqeust_id, fname)
+        self.data_type='Spectrogram'
+
+        self.read_fits()
+
+        self.spectrum = np.sum(self.counts, axis=0)
+
+    def peek(self, ax0=None, ax1=None, ax2=None, ax3=None):
+        """
+            preivew Science data
+        Arguments:
+        ax0: matplotlib axe 
+        ax0: matplotlib axe 
+        """
+        if not self.hdul:
+            print(f'Data not loaded. ')
+            return None
+
+        #((ax0, ax1), (ax2, ax3))=axs
+        if not any([ax0, ax1, ax2, ax3]):
+            _, ((ax0, ax1), (ax2, ax3)) = plt.subplots(2, 2, figsize=(8, 6))
+
+        if ax0:
+            X, Y = np.meshgrid(self.time,
+                               self.hdul['ENERGIES'].data['channel'])
+            im = ax0.pcolormesh(X, Y, np.transpose(
+                self.counts))  #pixel summed energy spectrum
+            ax0.set_yticks(self.hdul['ENERGIES'].data['channel'][::2])
+            ax0.set_yticklabels(self.energy_bin_names[::2])
+            fig = plt.gcf()
+            cbar = fig.colorbar(im, ax=ax0)
+            cbar.set_label('Counts')
+            ax0.set_title('Spectrogram')
+            ax0.set_ylabel('Energy range(keV')
+            ax0.set_xlabel(f"Seconds since {self.T0}s ")
+        if ax1:
+            #convert to 2d
+            ax1.plot(self.time, self.count_rates)
+            ax1.set_yscale('log')
+            ax1.set_ylabel('Counts / sec')
+            ax1.set_xlabel(f"Seconds since {self.T0}s ")
+        if ax2:
+            ax2.plot(self.ebins_low, self.spectrum, drawstyle='steps-post')
+            ax2.set_xscale('log')
+            ax2.set_yscale('log')
+            ax2.set_xlabel('Energy (keV)')
+            ax2.set_ylabel('Counts')
+        if ax3:
+            ax3.plot(self.time, self.timedel)
+            ax3.set_xlabel(f"Seconds since {self.T0}s ")
+            ax3.set_ylabel('Integration time (sec)')
+        plt.suptitle(f'L4 request #{self.request_id}')
+        plt.tight_layout()
+        return fig, ((ax0, ax1), (ax2, ax3))
+
+

Ancestors

+ +

Methods

+
+
+def peek(self, ax0=None, ax1=None, ax2=None, ax3=None) +
+
+

preivew Science data +Arguments: +ax0: matplotlib axe +ax0: matplotlib axe

+
+ +Expand source code + +
def peek(self, ax0=None, ax1=None, ax2=None, ax3=None):
+    """
+        preivew Science data
+    Arguments:
+    ax0: matplotlib axe 
+    ax0: matplotlib axe 
+    """
+    if not self.hdul:
+        print(f'Data not loaded. ')
+        return None
+
+    #((ax0, ax1), (ax2, ax3))=axs
+    if not any([ax0, ax1, ax2, ax3]):
+        _, ((ax0, ax1), (ax2, ax3)) = plt.subplots(2, 2, figsize=(8, 6))
+
+    if ax0:
+        X, Y = np.meshgrid(self.time,
+                           self.hdul['ENERGIES'].data['channel'])
+        im = ax0.pcolormesh(X, Y, np.transpose(
+            self.counts))  #pixel summed energy spectrum
+        ax0.set_yticks(self.hdul['ENERGIES'].data['channel'][::2])
+        ax0.set_yticklabels(self.energy_bin_names[::2])
+        fig = plt.gcf()
+        cbar = fig.colorbar(im, ax=ax0)
+        cbar.set_label('Counts')
+        ax0.set_title('Spectrogram')
+        ax0.set_ylabel('Energy range(keV')
+        ax0.set_xlabel(f"Seconds since {self.T0}s ")
+    if ax1:
+        #convert to 2d
+        ax1.plot(self.time, self.count_rates)
+        ax1.set_yscale('log')
+        ax1.set_ylabel('Counts / sec')
+        ax1.set_xlabel(f"Seconds since {self.T0}s ")
+    if ax2:
+        ax2.plot(self.ebins_low, self.spectrum, drawstyle='steps-post')
+        ax2.set_xscale('log')
+        ax2.set_yscale('log')
+        ax2.set_xlabel('Energy (keV)')
+        ax2.set_ylabel('Counts')
+    if ax3:
+        ax3.plot(self.time, self.timedel)
+        ax3.set_xlabel(f"Seconds since {self.T0}s ")
+        ax3.set_ylabel('Integration time (sec)')
+    plt.suptitle(f'L4 request #{self.request_id}')
+    plt.tight_layout()
+    return fig, ((ax0, ax1), (ax2, ax3))
+
+
+
+

Inherited members

+ +
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/time.html b/docs/stixdcpy/time.html new file mode 100644 index 0000000..26c3e10 --- /dev/null +++ b/docs/stixdcpy/time.html @@ -0,0 +1,310 @@ + + + + + + +stixdcpy.time API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.time

+
+
+
+ +Expand source code + +
#!/usr/bin/python3
+
+from datetime import datetime
+from dateutil import parser as dtparser
+
+
+def format_datetime(dt):
+    if isinstance(dt, datetime):
+        return dt.isoformat(timespec='milliseconds')
+    elif isinstance(dt, (int, float)):
+        return datetime.utcfromtimestamp(dt).isoformat(timespec='milliseconds')
+    elif isinstance(dt, str):
+        try:
+            return format_datetime(float(dt))
+        except ValueError:
+            return dt
+    else:
+        return '1970-01-01T00:00:00.000Z'
+
+
+def now():
+    return datetime.utcnow()
+
+
+def get_now(dtype='unix'):
+    utc_iso = datetime.utcnow().isoformat() + 'Z'
+    if dtype == 'unix':
+        return dtparser.parse(utc_iso).timestamp()
+    return utc_iso
+
+
+def utc2unix(utc):
+    if isinstance(utc, str):
+        if not utc.endswith('Z'):
+            utc += 'Z'
+        try:
+            return dtparser.parse(utc).timestamp()
+        except:
+            return 0
+    elif isinstance(utc, int) or isinstance(utc, float):
+        return utc
+    else:
+        return 0
+
+
+def utc2datetime(utc):
+    if not utc.endswith('Z'):
+        utc += 'Z'
+    try:
+        return dtparser.parse(utc)
+    except:
+        return None
+
+
+def unix2datetime(timestamp):
+    dt = None
+    if isinstance(timestamp, float):
+        dt = datetime.utcfromtimestamp(timestamp)
+    elif isinstance(timestamp, str):
+        try:
+            ts = float(timestamp)
+            dt = datetime.utcfromtimestamp(ts)
+        except ValueError:
+            dt = dtparser.parse(timestamp)
+    elif isinstance(timestamp, datetime.datetime):
+        dt = timestamp
+    return dt
+
+
+def datetime2unix(timestamp):
+    dt = None
+    if isinstance(timestamp, float):
+        dt = datetime.utcfromtimestamp(timestamp)
+    elif isinstance(timestamp, str):
+        try:
+            ts = float(timestamp)
+            dt = datetime.utcfromtimestamp(ts)
+        except ValueError:
+            dt = dtparser.parse(timestamp)
+    elif isinstance(timestamp, datetime.datetime):
+        dt = timestamp
+    if dt:
+        return dt.timestamp()
+    return 0
+
+
+def unix2utc(ts):
+    return datetime.utcfromtimestamp(ts).isoformat(timespec='milliseconds')
+
+
+def unix2datetime(unix_timestamp):
+    return datetime.utcfromtimestamp(unix_timestamp)
+
+
+
+
+
+
+
+

Functions

+
+
+def datetime2unix(timestamp) +
+
+
+
+ +Expand source code + +
def datetime2unix(timestamp):
+    dt = None
+    if isinstance(timestamp, float):
+        dt = datetime.utcfromtimestamp(timestamp)
+    elif isinstance(timestamp, str):
+        try:
+            ts = float(timestamp)
+            dt = datetime.utcfromtimestamp(ts)
+        except ValueError:
+            dt = dtparser.parse(timestamp)
+    elif isinstance(timestamp, datetime.datetime):
+        dt = timestamp
+    if dt:
+        return dt.timestamp()
+    return 0
+
+
+
+def format_datetime(dt) +
+
+
+
+ +Expand source code + +
def format_datetime(dt):
+    if isinstance(dt, datetime):
+        return dt.isoformat(timespec='milliseconds')
+    elif isinstance(dt, (int, float)):
+        return datetime.utcfromtimestamp(dt).isoformat(timespec='milliseconds')
+    elif isinstance(dt, str):
+        try:
+            return format_datetime(float(dt))
+        except ValueError:
+            return dt
+    else:
+        return '1970-01-01T00:00:00.000Z'
+
+
+
+def get_now(dtype='unix') +
+
+
+
+ +Expand source code + +
def get_now(dtype='unix'):
+    utc_iso = datetime.utcnow().isoformat() + 'Z'
+    if dtype == 'unix':
+        return dtparser.parse(utc_iso).timestamp()
+    return utc_iso
+
+
+
+def now() +
+
+
+
+ +Expand source code + +
def now():
+    return datetime.utcnow()
+
+
+
+def unix2datetime(unix_timestamp) +
+
+
+
+ +Expand source code + +
def unix2datetime(unix_timestamp):
+    return datetime.utcfromtimestamp(unix_timestamp)
+
+
+
+def unix2utc(ts) +
+
+
+
+ +Expand source code + +
def unix2utc(ts):
+    return datetime.utcfromtimestamp(ts).isoformat(timespec='milliseconds')
+
+
+
+def utc2datetime(utc) +
+
+
+
+ +Expand source code + +
def utc2datetime(utc):
+    if not utc.endswith('Z'):
+        utc += 'Z'
+    try:
+        return dtparser.parse(utc)
+    except:
+        return None
+
+
+
+def utc2unix(utc) +
+
+
+
+ +Expand source code + +
def utc2unix(utc):
+    if isinstance(utc, str):
+        if not utc.endswith('Z'):
+            utc += 'Z'
+        try:
+            return dtparser.parse(utc).timestamp()
+        except:
+            return 0
+    elif isinstance(utc, int) or isinstance(utc, float):
+        return utc
+    else:
+        return 0
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/transmission.html b/docs/stixdcpy/transmission.html new file mode 100644 index 0000000..2474972 --- /dev/null +++ b/docs/stixdcpy/transmission.html @@ -0,0 +1,1066 @@ + + + + + + +stixdcpy.transmission API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.transmission

+
+
+

calculation of stix transmission, taken from stixcore

+
+ +Expand source code + +
"""
+  calculation of stix transmission, taken from stixcore
+"""
+from collections import OrderedDict
+from functools import partial
+from stixdcpy import instrument as ins
+import astropy.units as u
+import numpy as np
+from astropy.table.table import Table
+from roentgen.absorption.material import Compound, MassAttenuationCoefficient, Material
+
+#from stixcore.config.reader import read_energy_channels
+
+__all__ = ['Transmission']
+
+MIL_SI = 0.0254 * u.mm
+
+# TODO move to configuration files
+COMPONENTS = OrderedDict([
+    ('front_window', [('solarblack', 0.005 * u.mm), ('be', 2 * u.mm)]),
+    ('rear_window', [('be', 1 * u.mm)]),
+    ('grid_covers', [('kapton', 4 * 2 * MIL_SI)]),
+    ('dem', [('kapton', 2 * 3 * MIL_SI)]),
+    ('attenuator', [('al', 0.6 * u.mm)]),
+    ('mli', [('al', 1000 * u.angstrom), ('kapton', 3 * MIL_SI),
+             ('al', 40 * 1000 * u.angstrom), ('mylar', 20 * 0.25 * MIL_SI),
+             ('pet', 21 * 0.005 * u.mm), ('kapton', 3 * MIL_SI),
+             ('al', 1000 * u.angstrom)]),
+    ('calibration_foil', [('al', 4 * 1000 * u.angstrom),
+                          ('kapton', 4 * 2 * MIL_SI)]),
+    ('dead_layer', [('te_o2', 392 * u.nm)]),
+])
+
+MATERIALS = OrderedDict([
+    ('al', ({
+        'Al': 1.0
+    }, 2.7 * u.g / u.cm**3)),
+    ('be', ({
+        'Be': 1.0
+    }, 1.85 * u.g / u.cm**3)),
+    ('kapton', ({
+        'H': 0.026362,
+        'C': 0.691133,
+        'N': 0.073270,
+        'O': 0.209235
+    }, 1.43 * u.g / u.cm**3)),
+    ('mylar', ({
+        'H': 0.041959,
+        'C': 0.625017,
+        'O': 0.333025
+    }, 1.38 * u.g / u.cm**3)),
+    ('pet', ({
+        'H': 0.041960,
+        'C': 0.625016,
+        'O': 0.333024
+    }, 1.370 * u.g / u.cm**3)),
+    ('solarblack_oxygen', ({
+        'H': 0.002,
+        'O': 0.415,
+        'Ca': 0.396,
+        'P': 0.187
+    }, 3.2 * u.g / u.cm**3)),
+    ('solarblack_carbon', ({
+        'C': 0.301,
+        'Ca': 0.503,
+        'P': 0.195
+    }, 3.2 * u.g / u.cm**3)),
+    ('te_o2', ({
+        'Te': 0.7995088158691722,
+        'O': 0.20049124678825841
+    }, 5.670 * u.g / u.cm**3)),
+])
+
+#    'Channel Number', 'Channel Edge', 'Energy Edge ', 'Elower', 'Eupper ',
+#    'BinWidth', 'dE/E', 'QL channel'
+default_energy_bins = [['0', '0', '0', '0', '4', '4', '2', 'n/a'],
+                       ['1', '1', '4', '4', '5', '1', '0.222', '0'],
+                       ['2', '2', '5', '5', '6', '1', '0.182', '0'],
+                       ['3', '3', '6', '6', '7', '1', '0.154', '0'],
+                       ['4', '4', '7', '7', '8', '1', '0.133', '0'],
+                       ['5', '5', '8', '8', '9', '1', '0.118', '0'],
+                       ['6', '6', '9', '9', '10', '1', '0.105', '0'],
+                       ['7', '7', '10', '10', '11', '1', '0.095', '1'],
+                       ['8', '8', '11', '11', '12', '1', '0.087', '1'],
+                       ['9', '9', '12', '12', '13', '1', '0.08', '1'],
+                       ['10', '10', '13', '13', '14', '1', '0.074', '1'],
+                       ['11', '11', '14', '14', '15', '1', '0.069', '1'],
+                       ['12', '12', '15', '15', '16', '1', '0.065', '2'],
+                       ['13', '13', '16', '16', '17', '1', '0.061', '2'],
+                       ['14', '14', '18', '18', '20', '2', '0.105', '2'],
+                       ['15', '15', '20', '20', '22', '2', '0.095', '2'],
+                       ['16', '16', '22', '22', '25', '3', '0.128', '2'],
+                       ['17', '17', '25', '25', '28', '3', '0.113', '3'],
+                       ['18', '18', '28', '28', '32', '4', '0.133', '3'],
+                       ['19', '19', '32', '32', '36', '4', '0.118', '3'],
+                       ['20', '20', '36', '36', '40', '4', '0.105', '3'],
+                       ['21', '21', '40', '40', '45', '5', '0.118', '3'],
+                       ['22', '22', '45', '45', '50', '5', '0.105', '3'],
+                       ['23', '23', '50', '50', '56', '6', '0.113', '4'],
+                       ['24', '24', '56', '56', '63', '7', '0.118', '4'],
+                       ['25', '25', '63', '63', '70', '7', '0.105', '4'],
+                       ['26', '26', '70', '70', '76', '6', '0.082', '4'],
+                       ['27', '27', '76', '76', '84', '8', '0.1', '4'],
+                       ['28', '28', '84', '84', '100', '16', '0.174', '4'],
+                       ['29', '29', '100', '100', '120', '20', '0.182', '4'],
+                       ['30', '30', '120', '120', '150', '30', '0.222', '4'],
+                       [
+                           '31', '31', '150', '150', 'maxADC', 'n/a', 'n/a',
+                           'n/a'
+                       ], ['', '32', 'max ADC', '', '', '', '', '']]
+
+
+def float_def(value, default=np.inf):
+    """Parse the value into a float or return the default value.
+
+    Parameters
+    ----------
+    value : `str`
+        the value to parse
+    default : `double`, optional
+        default value to return in case of pasring errors, by default numpy.inf
+
+    Returns
+    -------
+    `double`
+        the parsed value
+    """
+    try:
+        return float(value)
+    except ValueError:
+        return default
+
+
+def int_def(value, default=0):
+    """Parse the value into a int or return the default value.
+
+    Parameters
+    ----------
+    value : `str`
+        the value to parse
+    default : `int`, optional
+        default value to return in case of pasring errors, by default 0
+
+    Returns
+    -------
+    `int`
+        the parsed value
+    """
+    try:
+        return int(value)
+    except ValueError:
+        return default
+
+
+# TODO get file from config
+
+
+class Transmission:
+    """
+    Calculate the energy dependant transmission of X-ray through the instrument
+    """
+    def __init__(self, solarblack='solarblack_carbon'):
+        """
+        Create a new instance of the transmission with the given solar black composition.
+
+        Parameters
+        ----------
+
+        solarblack : `str` optional
+            The SolarBlack composition to use.
+        """
+        if solarblack not in ['solarblack_oxygen', 'solarblack_carbon']:
+            raise ValueError(
+                "solarblack must be either 'solarblack_oxygen' or "
+                "'solarblack_carbon'.")
+
+        self.solarblack = solarblack
+        self.materials = MATERIALS
+        self.components = COMPONENTS
+        self.components = dict()
+
+        for name, layers in COMPONENTS.items():
+            parts = []
+            for material, thickness in layers:
+                if material == 'solarblack':
+                    material = self.solarblack
+                mass_frac, den = MATERIALS[material]
+                if material == 'al':
+                    thickness = thickness * 0.8
+                parts.append(
+                    self.create_material(name=material,
+                                         fractional_masses=mass_frac,
+                                         thickness=thickness,
+                                         density=den))
+            self.components[name] = Compound(parts)
+
+    def get_transmission(self, energies, attenuator=False):
+        """
+        Get the transmission for each detector at the center of the given energy bins.
+
+        If energies are not supplied will evaluate at standard science energy channels
+
+        Parameters
+        ----------
+        energies : `astropy.units.Quantity`, optional
+            The energies to evaluate the transmission
+        attenuator : `bool`, optional
+            True for attenuator in X-ray path, False for attenuator not in X-ray path
+
+        Returns
+        -------
+        `astropy.table.Table`
+            Table containing the transmission values for each energy and detector
+        """
+        base_comps = [
+            self.components[name] for name in [
+                'front_window', 'rear_window', 'dem', 'mli',
+                'calibration_foil', 'dead_layer'
+            ]
+        ]
+
+        #if energies is None:
+        energies = energies * u.keV
+        #    self.energies = [ENERGY_CHANNELS[i].e_lower for i in range(1, 32)] * u.keV
+
+        if attenuator:
+            base_comps.append(self.components['attenuator'])
+
+        base = Compound(base_comps)
+        base_trans = base.transmission(energies)
+
+        fine = Compound(base_comps + [self.components['grid_covers']])
+        fine_trans = fine.transmission(energies)
+
+        # TODO need to move to configuration db
+        fine_grids = np.array([11, 13, 18, 12, 19, 17]) - 1
+        detector_transmission = Table()
+        # transmission['sci_channel'] = range(1, 31)
+        detector_transmission['energies'] = energies
+        for i in range(32):
+            name = f'det-{i}'
+            if np.isin(i, fine_grids):
+                detector_transmission[name] = fine_trans
+            else:
+                detector_transmission[name] = base_trans
+        return detector_transmission
+
+    def get_detector_transmission(self,
+                                  detector_id,
+                                  energy_bins,
+                                  attenuator=False):
+        '''
+            get transmission for detector
+            Arguments
+            ---------
+            detector:  ranges from 0...31 
+            energy_bins:   32 x 2 array like [[e_bin_0_low, ebin_0_up], ...[]]
+            Returns
+            --------
+            transmission for the energy bins
+            
+        '''
+        base_comps = [
+            self.components[name] for name in [
+                'front_window', 'rear_window', 'dem', 'mli',
+                'calibration_foil', 'dead_layer'
+            ]
+        ]
+
+        if attenuator:
+            base_comps.append(self.components['attenuator'])
+
+        fine_grids = [10, 12, 17, 11, 18, 16]
+
+        if detector_id in fine_grids:
+            comp = Compound(base_comps + [self.components['grid_covers']])
+        else:
+            comp = Compound(base_comps)
+
+        ebins_1d = energy_bins.reshape(-1) * u.keV
+        #convert energy bin ranges to 1d
+        det_trans = comp.transmission(ebins_1d)
+        mean_trans = np.mean(det_trans.reshape((-1, 2)), axis=1)
+        #calculate mean energy transmission factors for energy bins
+        return mean_trans
+
+    def get_transmission_by_component(self):
+        """
+        Get the contributions to the total transmission by broken down by component.
+
+        Returns
+        -------
+        `dict`
+            Entries are Compounds for each component
+        """
+        return self.components
+
+    def get_transmission_by_material(self):
+        """
+        Get the contribution to the transmission by total thickness for each material.
+
+        Layers of the same materials are combined to return one instance with the total thickness.
+
+        Returns
+        -------
+        `dict`
+            Entries are meterials with the total thickness for that material.
+        """
+        material_thickness = dict()
+        for name, layers in COMPONENTS.items():
+            for material_name, thickness in layers:
+                if material_name == 'solarblack':
+                    material_name = self.solarblack
+                if material_name in material_thickness.keys():
+                    material_thickness[material_name] += thickness.to('mm')
+                else:
+                    material_thickness[material_name] = thickness.to('mm')
+        res = {}
+        for name, thickness in material_thickness.items():
+            frac_mass, density = self.materials[name]
+            mat = self.create_material(name=name,
+                                       fractional_masses=frac_mass,
+                                       density=density,
+                                       thickness=thickness)
+            res[name] = mat
+
+        return res
+    @classmethod
+    def get_stix_ebins_transmission(cls, ebins=ins.ebins):
+        pass
+    @classmethod
+    def create_material(cls,
+                        name=None,
+                        fractional_masses=None,
+                        thickness=None,
+                        density=None):
+        """
+        Create a new material given the composition and fractional masses.
+
+        Parameters
+        ----------
+        name : `str`
+            Name of the meterial
+        fractional_masses : `dict`
+            The element and fractional masses of the material e.g. `{'H': 0.031, 'O': 0.969}`
+        thickness : `astropy.units.Quantity`
+            Thickness of the material
+        density : `astropy.units.Quantity`
+            Density of the material
+
+        Returns
+        -------
+        `roentgen.absorption.material.Material`
+            The material
+        """
+        material = Material('h', thickness, density)
+        material.name = name
+        # probably don't need this
+        material.density = density
+
+        # TODO remove in favour of upstream fix when completed
+        #  see https://github.com/ehsteve/roentgen/issues/26
+        def func(composition, e):
+            return sum([
+                MassAttenuationCoefficient(element).func(e) * frac_mass
+                for element, frac_mass in composition.items()
+            ])
+
+        material_func = partial(func, fractional_masses)
+
+        material.mass_attenuation_coefficient.func = material_func
+        return material
+
+
+def get_detector_absorption(energies=None):
+    mass_fraction = {'Te': 0.531644, 'Cd': 0.4683554}
+    density = 5.85 * u.g / u.cm**3
+    thickness = 1 * u.mm
+    material = Transmission.create_material(name='cdte',
+                                            fractional_masses=mass_fraction,
+                                            thickness=thickness,
+                                            density=density)
+    if energies is None:
+        energies = np.linspace(2, 150, 1001)
+    energies_keV = energies * u.keV
+    absorption = material.absorption(energies_keV)
+    return energies, absorption
+
+
+#def get_transmission(energies):
+#    return trans.get_transmission(energies)
+if __name__ == '__main__':
+    energies = np.linspace(2, 150, 1001)
+    #tr=Transmission()
+    #t=tr.get_transmission(energies)
+    #t.pprint()
+    #print(t['det-0'][0])
+    get_detector_absorption()
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class Transmission +(solarblack='solarblack_carbon') +
+
+

Calculate the energy dependant transmission of X-ray through the instrument

+

Create a new instance of the transmission with the given solar black composition.

+

Parameters

+
+
solarblack : str</code> optional
+
The SolarBlack composition to use.
+
+
+ +Expand source code + +
class Transmission:
+    """
+    Calculate the energy dependant transmission of X-ray through the instrument
+    """
+    def __init__(self, solarblack='solarblack_carbon'):
+        """
+        Create a new instance of the transmission with the given solar black composition.
+
+        Parameters
+        ----------
+
+        solarblack : `str` optional
+            The SolarBlack composition to use.
+        """
+        if solarblack not in ['solarblack_oxygen', 'solarblack_carbon']:
+            raise ValueError(
+                "solarblack must be either 'solarblack_oxygen' or "
+                "'solarblack_carbon'.")
+
+        self.solarblack = solarblack
+        self.materials = MATERIALS
+        self.components = COMPONENTS
+        self.components = dict()
+
+        for name, layers in COMPONENTS.items():
+            parts = []
+            for material, thickness in layers:
+                if material == 'solarblack':
+                    material = self.solarblack
+                mass_frac, den = MATERIALS[material]
+                if material == 'al':
+                    thickness = thickness * 0.8
+                parts.append(
+                    self.create_material(name=material,
+                                         fractional_masses=mass_frac,
+                                         thickness=thickness,
+                                         density=den))
+            self.components[name] = Compound(parts)
+
+    def get_transmission(self, energies, attenuator=False):
+        """
+        Get the transmission for each detector at the center of the given energy bins.
+
+        If energies are not supplied will evaluate at standard science energy channels
+
+        Parameters
+        ----------
+        energies : `astropy.units.Quantity`, optional
+            The energies to evaluate the transmission
+        attenuator : `bool`, optional
+            True for attenuator in X-ray path, False for attenuator not in X-ray path
+
+        Returns
+        -------
+        `astropy.table.Table`
+            Table containing the transmission values for each energy and detector
+        """
+        base_comps = [
+            self.components[name] for name in [
+                'front_window', 'rear_window', 'dem', 'mli',
+                'calibration_foil', 'dead_layer'
+            ]
+        ]
+
+        #if energies is None:
+        energies = energies * u.keV
+        #    self.energies = [ENERGY_CHANNELS[i].e_lower for i in range(1, 32)] * u.keV
+
+        if attenuator:
+            base_comps.append(self.components['attenuator'])
+
+        base = Compound(base_comps)
+        base_trans = base.transmission(energies)
+
+        fine = Compound(base_comps + [self.components['grid_covers']])
+        fine_trans = fine.transmission(energies)
+
+        # TODO need to move to configuration db
+        fine_grids = np.array([11, 13, 18, 12, 19, 17]) - 1
+        detector_transmission = Table()
+        # transmission['sci_channel'] = range(1, 31)
+        detector_transmission['energies'] = energies
+        for i in range(32):
+            name = f'det-{i}'
+            if np.isin(i, fine_grids):
+                detector_transmission[name] = fine_trans
+            else:
+                detector_transmission[name] = base_trans
+        return detector_transmission
+
+    def get_detector_transmission(self,
+                                  detector_id,
+                                  energy_bins,
+                                  attenuator=False):
+        '''
+            get transmission for detector
+            Arguments
+            ---------
+            detector:  ranges from 0...31 
+            energy_bins:   32 x 2 array like [[e_bin_0_low, ebin_0_up], ...[]]
+            Returns
+            --------
+            transmission for the energy bins
+            
+        '''
+        base_comps = [
+            self.components[name] for name in [
+                'front_window', 'rear_window', 'dem', 'mli',
+                'calibration_foil', 'dead_layer'
+            ]
+        ]
+
+        if attenuator:
+            base_comps.append(self.components['attenuator'])
+
+        fine_grids = [10, 12, 17, 11, 18, 16]
+
+        if detector_id in fine_grids:
+            comp = Compound(base_comps + [self.components['grid_covers']])
+        else:
+            comp = Compound(base_comps)
+
+        ebins_1d = energy_bins.reshape(-1) * u.keV
+        #convert energy bin ranges to 1d
+        det_trans = comp.transmission(ebins_1d)
+        mean_trans = np.mean(det_trans.reshape((-1, 2)), axis=1)
+        #calculate mean energy transmission factors for energy bins
+        return mean_trans
+
+    def get_transmission_by_component(self):
+        """
+        Get the contributions to the total transmission by broken down by component.
+
+        Returns
+        -------
+        `dict`
+            Entries are Compounds for each component
+        """
+        return self.components
+
+    def get_transmission_by_material(self):
+        """
+        Get the contribution to the transmission by total thickness for each material.
+
+        Layers of the same materials are combined to return one instance with the total thickness.
+
+        Returns
+        -------
+        `dict`
+            Entries are meterials with the total thickness for that material.
+        """
+        material_thickness = dict()
+        for name, layers in COMPONENTS.items():
+            for material_name, thickness in layers:
+                if material_name == 'solarblack':
+                    material_name = self.solarblack
+                if material_name in material_thickness.keys():
+                    material_thickness[material_name] += thickness.to('mm')
+                else:
+                    material_thickness[material_name] = thickness.to('mm')
+        res = {}
+        for name, thickness in material_thickness.items():
+            frac_mass, density = self.materials[name]
+            mat = self.create_material(name=name,
+                                       fractional_masses=frac_mass,
+                                       density=density,
+                                       thickness=thickness)
+            res[name] = mat
+
+        return res
+    @classmethod
+    def get_stix_ebins_transmission(cls, ebins=ins.ebins):
+        pass
+    @classmethod
+    def create_material(cls,
+                        name=None,
+                        fractional_masses=None,
+                        thickness=None,
+                        density=None):
+        """
+        Create a new material given the composition and fractional masses.
+
+        Parameters
+        ----------
+        name : `str`
+            Name of the meterial
+        fractional_masses : `dict`
+            The element and fractional masses of the material e.g. `{'H': 0.031, 'O': 0.969}`
+        thickness : `astropy.units.Quantity`
+            Thickness of the material
+        density : `astropy.units.Quantity`
+            Density of the material
+
+        Returns
+        -------
+        `roentgen.absorption.material.Material`
+            The material
+        """
+        material = Material('h', thickness, density)
+        material.name = name
+        # probably don't need this
+        material.density = density
+
+        # TODO remove in favour of upstream fix when completed
+        #  see https://github.com/ehsteve/roentgen/issues/26
+        def func(composition, e):
+            return sum([
+                MassAttenuationCoefficient(element).func(e) * frac_mass
+                for element, frac_mass in composition.items()
+            ])
+
+        material_func = partial(func, fractional_masses)
+
+        material.mass_attenuation_coefficient.func = material_func
+        return material
+
+

Static methods

+
+
+def create_material(name=None, fractional_masses=None, thickness=None, density=None) +
+
+

Create a new material given the composition and fractional masses.

+

Parameters

+
+
name : str
+
Name of the meterial
+
fractional_masses : dict
+
The element and fractional masses of the material e.g. {'H': 0.031, 'O': 0.969}
+
thickness : astropy.units.Quantity
+
Thickness of the material
+
density : astropy.units.Quantity
+
Density of the material
+
+

Returns

+

roentgen.absorption.material.Material +The material

+
+ +Expand source code + +
@classmethod
+def create_material(cls,
+                    name=None,
+                    fractional_masses=None,
+                    thickness=None,
+                    density=None):
+    """
+    Create a new material given the composition and fractional masses.
+
+    Parameters
+    ----------
+    name : `str`
+        Name of the meterial
+    fractional_masses : `dict`
+        The element and fractional masses of the material e.g. `{'H': 0.031, 'O': 0.969}`
+    thickness : `astropy.units.Quantity`
+        Thickness of the material
+    density : `astropy.units.Quantity`
+        Density of the material
+
+    Returns
+    -------
+    `roentgen.absorption.material.Material`
+        The material
+    """
+    material = Material('h', thickness, density)
+    material.name = name
+    # probably don't need this
+    material.density = density
+
+    # TODO remove in favour of upstream fix when completed
+    #  see https://github.com/ehsteve/roentgen/issues/26
+    def func(composition, e):
+        return sum([
+            MassAttenuationCoefficient(element).func(e) * frac_mass
+            for element, frac_mass in composition.items()
+        ])
+
+    material_func = partial(func, fractional_masses)
+
+    material.mass_attenuation_coefficient.func = material_func
+    return material
+
+
+
+def get_stix_ebins_transmission(ebins=array([[ +0., +4.], +[ +4., +5.], +[ +5., +6.], +[ +6., +7.], +[ +7., +8.], +[ +8., +9.], +[ +9., +10.], +[ 10., +11.], +[ 11., +12.], +[ 12., +13.], +[ 13., +14.], +[ 14., +15.], +[ 15., +16.], +[ 16., +18.], +[ 18., +20.], +[ 20., +22.], +[ 22., +25.], +[ 25., +28.], +[ 28., +32.], +[ 32., +36.], +[ 36., +40.], +[ 40., +45.], +[ 45., +50.], +[ 50., +56.], +[ 56., +63.], +[ 63., +70.], +[ 70., +76.], +[ 76., +84.], +[ 84., 100.], +[100., 120.], +[120., 150.], +[150., +inf]])) +
+
+
+
+ +Expand source code + +
@classmethod
+def get_stix_ebins_transmission(cls, ebins=ins.ebins):
+    pass
+
+
+
+

Methods

+
+
+def get_detector_transmission(self, detector_id, energy_bins, attenuator=False) +
+
+

get transmission for detector +Arguments

+
+
+
detector :  ranges from 0…31
+
 
+
energy_bins :  +32 x 2 array like [[e_bin_0_low, ebin_0_up], …[]]
+
 
+
+

Returns

+
+
transmission for the energy bins
+
 
+
+
+ +Expand source code + +
def get_detector_transmission(self,
+                              detector_id,
+                              energy_bins,
+                              attenuator=False):
+    '''
+        get transmission for detector
+        Arguments
+        ---------
+        detector:  ranges from 0...31 
+        energy_bins:   32 x 2 array like [[e_bin_0_low, ebin_0_up], ...[]]
+        Returns
+        --------
+        transmission for the energy bins
+        
+    '''
+    base_comps = [
+        self.components[name] for name in [
+            'front_window', 'rear_window', 'dem', 'mli',
+            'calibration_foil', 'dead_layer'
+        ]
+    ]
+
+    if attenuator:
+        base_comps.append(self.components['attenuator'])
+
+    fine_grids = [10, 12, 17, 11, 18, 16]
+
+    if detector_id in fine_grids:
+        comp = Compound(base_comps + [self.components['grid_covers']])
+    else:
+        comp = Compound(base_comps)
+
+    ebins_1d = energy_bins.reshape(-1) * u.keV
+    #convert energy bin ranges to 1d
+    det_trans = comp.transmission(ebins_1d)
+    mean_trans = np.mean(det_trans.reshape((-1, 2)), axis=1)
+    #calculate mean energy transmission factors for energy bins
+    return mean_trans
+
+
+
+def get_transmission(self, energies, attenuator=False) +
+
+

Get the transmission for each detector at the center of the given energy bins.

+

If energies are not supplied will evaluate at standard science energy channels

+

Parameters

+
+
energies : astropy.units.Quantity, optional
+
The energies to evaluate the transmission
+
attenuator : bool, optional
+
True for attenuator in X-ray path, False for attenuator not in X-ray path
+
+

Returns

+

astropy.table.Table +Table containing the transmission values for each energy and detector

+
+ +Expand source code + +
def get_transmission(self, energies, attenuator=False):
+    """
+    Get the transmission for each detector at the center of the given energy bins.
+
+    If energies are not supplied will evaluate at standard science energy channels
+
+    Parameters
+    ----------
+    energies : `astropy.units.Quantity`, optional
+        The energies to evaluate the transmission
+    attenuator : `bool`, optional
+        True for attenuator in X-ray path, False for attenuator not in X-ray path
+
+    Returns
+    -------
+    `astropy.table.Table`
+        Table containing the transmission values for each energy and detector
+    """
+    base_comps = [
+        self.components[name] for name in [
+            'front_window', 'rear_window', 'dem', 'mli',
+            'calibration_foil', 'dead_layer'
+        ]
+    ]
+
+    #if energies is None:
+    energies = energies * u.keV
+    #    self.energies = [ENERGY_CHANNELS[i].e_lower for i in range(1, 32)] * u.keV
+
+    if attenuator:
+        base_comps.append(self.components['attenuator'])
+
+    base = Compound(base_comps)
+    base_trans = base.transmission(energies)
+
+    fine = Compound(base_comps + [self.components['grid_covers']])
+    fine_trans = fine.transmission(energies)
+
+    # TODO need to move to configuration db
+    fine_grids = np.array([11, 13, 18, 12, 19, 17]) - 1
+    detector_transmission = Table()
+    # transmission['sci_channel'] = range(1, 31)
+    detector_transmission['energies'] = energies
+    for i in range(32):
+        name = f'det-{i}'
+        if np.isin(i, fine_grids):
+            detector_transmission[name] = fine_trans
+        else:
+            detector_transmission[name] = base_trans
+    return detector_transmission
+
+
+
+def get_transmission_by_component(self) +
+
+

Get the contributions to the total transmission by broken down by component.

+

Returns

+

dict +Entries are Compounds for each component

+
+ +Expand source code + +
def get_transmission_by_component(self):
+    """
+    Get the contributions to the total transmission by broken down by component.
+
+    Returns
+    -------
+    `dict`
+        Entries are Compounds for each component
+    """
+    return self.components
+
+
+
+def get_transmission_by_material(self) +
+
+

Get the contribution to the transmission by total thickness for each material.

+

Layers of the same materials are combined to return one instance with the total thickness.

+

Returns

+

dict +Entries are meterials with the total thickness for that material.

+
+ +Expand source code + +
def get_transmission_by_material(self):
+    """
+    Get the contribution to the transmission by total thickness for each material.
+
+    Layers of the same materials are combined to return one instance with the total thickness.
+
+    Returns
+    -------
+    `dict`
+        Entries are meterials with the total thickness for that material.
+    """
+    material_thickness = dict()
+    for name, layers in COMPONENTS.items():
+        for material_name, thickness in layers:
+            if material_name == 'solarblack':
+                material_name = self.solarblack
+            if material_name in material_thickness.keys():
+                material_thickness[material_name] += thickness.to('mm')
+            else:
+                material_thickness[material_name] = thickness.to('mm')
+    res = {}
+    for name, thickness in material_thickness.items():
+        frac_mass, density = self.materials[name]
+        mat = self.create_material(name=name,
+                                   fractional_masses=frac_mass,
+                                   density=density,
+                                   thickness=thickness)
+        res[name] = mat
+
+    return res
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/docs/stixdcpy/transmission_backup.html b/docs/stixdcpy/transmission_backup.html new file mode 100644 index 0000000..d98be6c --- /dev/null +++ b/docs/stixdcpy/transmission_backup.html @@ -0,0 +1,1067 @@ + + + + + + +stixdcpy.transmission_backup API documentation + + + + + + + + + + + +
+
+
+

Module stixdcpy.transmission_backup

+
+
+
+ +Expand source code + +
from collections import OrderedDict
+from functools import partial
+
+import astropy.units as u
+import numpy as np
+from astropy.table.table import Table
+from roentgen.absorption.material import Compound, MassAttenuationCoefficient, Material
+
+#from stixcore.config.reader import read_energy_channels
+
+__all__ = ['Transmission']
+
+MIL_SI = 0.0254 * u.mm
+
+# TODO move to configuration files
+COMPONENTS = OrderedDict([
+    ('front_window', [('solarblack', 0.005 * u.mm), ('be', 2 * u.mm)]),
+    ('rear_window', [('be', 1 * u.mm)]),
+    ('grid_covers', [('kapton', 4 * 2 * MIL_SI)]),
+    ('dem', [('kapton', 2 * 3 * MIL_SI)]),
+    ('attenuator', [('al', 0.6 * u.mm)]),
+    ('mli', [('al', 1000 * u.angstrom), ('kapton', 3 * MIL_SI),
+             ('al', 40 * 1000 * u.angstrom), ('mylar', 20 * 0.25 * MIL_SI),
+             ('pet', 21 * 0.005 * u.mm), ('kapton', 3 * MIL_SI),
+             ('al', 1000 * u.angstrom)]),
+    ('calibration_foil', [('al', 4 * 1000 * u.angstrom),
+                          ('kapton', 4 * 2 * MIL_SI)]),
+    ('dead_layer', [('te_o2', 392 * u.nm)]),
+])
+
+MATERIALS = OrderedDict([
+    ('al', ({
+        'Al': 1.0
+    }, 2.7 * u.g / u.cm**3)),
+    ('be', ({
+        'Be': 1.0
+    }, 1.85 * u.g / u.cm**3)),
+    ('kapton', ({
+        'H': 0.026362,
+        'C': 0.691133,
+        'N': 0.073270,
+        'O': 0.209235
+    }, 1.43 * u.g / u.cm**3)),
+    ('mylar', ({
+        'H': 0.041959,
+        'C': 0.625017,
+        'O': 0.333025
+    }, 1.38 * u.g / u.cm**3)),
+    ('pet', ({
+        'H': 0.041960,
+        'C': 0.625016,
+        'O': 0.333024
+    }, 1.370 * u.g / u.cm**3)),
+    ('solarblack_oxygen', ({
+        'H': 0.002,
+        'O': 0.415,
+        'Ca': 0.396,
+        'P': 0.187
+    }, 3.2 * u.g / u.cm**3)),
+    ('solarblack_carbon', ({
+        'C': 0.301,
+        'Ca': 0.503,
+        'P': 0.195
+    }, 3.2 * u.g / u.cm**3)),
+    ('te_o2', ({
+        'Te': 0.7995088158691722,
+        'O': 0.20049124678825841
+    }, 5.670 * u.g / u.cm**3)),
+])
+
+#    'Channel Number', 'Channel Edge', 'Energy Edge ', 'Elower', 'Eupper ',
+#    'BinWidth', 'dE/E', 'QL channel'
+default_energy_bins = [['0', '0', '0', '0', '4', '4', '2', 'n/a'],
+                       ['1', '1', '4', '4', '5', '1', '0.222', '0'],
+                       ['2', '2', '5', '5', '6', '1', '0.182', '0'],
+                       ['3', '3', '6', '6', '7', '1', '0.154', '0'],
+                       ['4', '4', '7', '7', '8', '1', '0.133', '0'],
+                       ['5', '5', '8', '8', '9', '1', '0.118', '0'],
+                       ['6', '6', '9', '9', '10', '1', '0.105', '0'],
+                       ['7', '7', '10', '10', '11', '1', '0.095', '1'],
+                       ['8', '8', '11', '11', '12', '1', '0.087', '1'],
+                       ['9', '9', '12', '12', '13', '1', '0.08', '1'],
+                       ['10', '10', '13', '13', '14', '1', '0.074', '1'],
+                       ['11', '11', '14', '14', '15', '1', '0.069', '1'],
+                       ['12', '12', '15', '15', '16', '1', '0.065', '2'],
+                       ['13', '13', '16', '16', '17', '1', '0.061', '2'],
+                       ['14', '14', '18', '18', '20', '2', '0.105', '2'],
+                       ['15', '15', '20', '20', '22', '2', '0.095', '2'],
+                       ['16', '16', '22', '22', '25', '3', '0.128', '2'],
+                       ['17', '17', '25', '25', '28', '3', '0.113', '3'],
+                       ['18', '18', '28', '28', '32', '4', '0.133', '3'],
+                       ['19', '19', '32', '32', '36', '4', '0.118', '3'],
+                       ['20', '20', '36', '36', '40', '4', '0.105', '3'],
+                       ['21', '21', '40', '40', '45', '5', '0.118', '3'],
+                       ['22', '22', '45', '45', '50', '5', '0.105', '3'],
+                       ['23', '23', '50', '50', '56', '6', '0.113', '4'],
+                       ['24', '24', '56', '56', '63', '7', '0.118', '4'],
+                       ['25', '25', '63', '63', '70', '7', '0.105', '4'],
+                       ['26', '26', '70', '70', '76', '6', '0.082', '4'],
+                       ['27', '27', '76', '76', '84', '8', '0.1', '4'],
+                       ['28', '28', '84', '84', '100', '16', '0.174', '4'],
+                       ['29', '29', '100', '100', '120', '20', '0.182', '4'],
+                       ['30', '30', '120', '120', '150', '30', '0.222', '4'],
+                       [
+                           '31', '31', '150', '150', 'maxADC', 'n/a', 'n/a',
+                           'n/a'
+                       ], ['', '32', 'max ADC', '', '', '', '', '']]
+
+
+def float_def(value, default=np.inf):
+    """Parse the value into a float or return the default value.
+
+    Parameters
+    ----------
+    value : `str`
+        the value to parse
+    default : `double`, optional
+        default value to return in case of pasring errors, by default numpy.inf
+
+    Returns
+    -------
+    `double`
+        the parsed value
+    """
+    try:
+        return float(value)
+    except ValueError:
+        return default
+
+
+def int_def(value, default=0):
+    """Parse the value into a int or return the default value.
+
+    Parameters
+    ----------
+    value : `str`
+        the value to parse
+    default : `int`, optional
+        default value to return in case of pasring errors, by default 0
+
+    Returns
+    -------
+    `int`
+        the parsed value
+    """
+    try:
+        return int(value)
+    except ValueError:
+        return default
+
+
+# TODO get file from config
+'''
+class EnergyChannel:
+    """Represent a STIX energy channel.
+
+    Attributes
+    ----------
+    channel_edge : ´int´
+        chanel idx
+    energy_edge : ´int´
+        edge on energy axis
+    e_lower : ´float´
+        start of the energy band in keV
+    e_upper : ´float´
+        end of the energy band in keV
+    bin_width : ´float´
+        width of the energy band in keV
+    dE_E : ´float´
+        TODO
+    """
+
+    def __init__(self, *, channel_edge, energy_edge, e_lower, e_upper, bin_width, dE_E):
+        self.channel_edge = channel_edge
+        self.energy_edge = energy_edge
+        self.e_lower = e_lower
+        self.e_upper = e_upper
+        self.bin_width = bin_width
+        self.dE_E = dE_E
+
+    def __repr__(self):
+        return f'{self.__class__.__name__}(channel_edge={self.channel_edge}, ' +\
+               f'energy_edge={self.energy_edge}, e_lower={self.e_lower}, e_upper={self.e_upper},' +\
+               f' bin_width={self.bin_width}, dE_E={self.dE_E})'
+def read_energy_channels(energy_bin_config=default_energy_bins):
+    """Read the energy channels from the configuration file.
+
+    Parameters
+    ----------
+    path : `pathlib.Path`
+        path to the config file
+
+    Returns
+    -------
+    `dict`
+        set of `EnergyChannel` accessible by index
+    """
+    energy_channels = dict()
+    if energy_bin_config:
+        for row in energy_bin_config:
+        
+            idx = int_def(row[0], -1)
+            if idx == -1:
+                continue
+            energy_channels[idx] = EnergyChannel(
+                channel_edge=int_def(row[1]),
+                energy_edge=int_def(row[2]),
+                e_lower=float_def(row[3]),
+                e_upper=float_def(row[4]),
+                bin_width=float_def(row[5]),
+                dE_E=float_def(row[6])
+            )
+
+    return energy_channels
+
+#ENERGY_CHANNELS = read_energy_channels(default_energy_bins)
+'''
+
+
+class Transmission:
+    """
+    Calculate the energy dependant transmission of X-ray through the instrument
+    """
+    def __init__(self, solarblack='solarblack_carbon'):
+        """
+        Create a new instance of the transmission with the given solar black composition.
+
+        Parameters
+        ----------
+
+        solarblack : `str` optional
+            The SolarBlack composition to use.
+        """
+        if solarblack not in ['solarblack_oxygen', 'solarblack_carbon']:
+            raise ValueError(
+                "solarblack must be either 'solarblack_oxygen' or "
+                "'solarblack_carbon'.")
+
+        self.solarblack = solarblack
+        self.materials = MATERIALS
+        self.components = COMPONENTS
+        self.components = dict()
+
+        for name, layers in COMPONENTS.items():
+            parts = []
+            for material, thickness in layers:
+                if material == 'solarblack':
+                    material = self.solarblack
+                mass_frac, den = MATERIALS[material]
+                if material == 'al':
+                    thickness = thickness * 0.8
+                parts.append(
+                    self.create_material(name=material,
+                                         fractional_masses=mass_frac,
+                                         thickness=thickness,
+                                         density=den))
+            self.components[name] = Compound(parts)
+
+    def get_transmission(self, energies, attenuator=False):
+        """
+        Get the transmission for each detector at the center of the given energy bins.
+
+        If energies are not supplied will evaluate at standard science energy channels
+
+        Parameters
+        ----------
+        energies : `astropy.units.Quantity`, optional
+            The energies to evaluate the transmission
+        attenuator : `bool`, optional
+            True for attenuator in X-ray path, False for attenuator not in X-ray path
+
+        Returns
+        -------
+        `astropy.table.Table`
+            Table containing the transmission values for each energy and detector
+        """
+        base_comps = [
+            self.components[name] for name in [
+                'front_window', 'rear_window', 'dem', 'mli',
+                'calibration_foil', 'dead_layer'
+            ]
+        ]
+
+        #if energies is None:
+        energies = energies * u.keV
+        #    self.energies = [ENERGY_CHANNELS[i].e_lower for i in range(1, 32)] * u.keV
+
+        if attenuator:
+            base_comps.append(self.components['attenuator'])
+
+        base = Compound(base_comps)
+        base_trans = base.transmission(energies)
+
+        fine = Compound(base_comps + [self.components['grid_covers']])
+        fine_trans = fine.transmission(energies)
+
+        # TODO need to move to configuration db
+        fine_grids = np.array([11, 13, 18, 12, 19, 17]) - 1
+        detector_transmission = Table()
+        # transmission['sci_channel'] = range(1, 31)
+        detector_transmission['energies'] = energies
+        for i in range(32):
+            name = f'det-{i}'
+            if np.isin(i, fine_grids):
+                detector_transmission[name] = fine_trans
+            else:
+                detector_transmission[name] = base_trans
+        return detector_transmission
+
+    def get_detector_transmission(self,
+                                  detector_id,
+                                  energy_bins,
+                                  attenuator=False):
+        '''
+            get transmission for detector
+            Arguments
+            ---------
+            detector:  ranges from 0...31 
+            energy_bins:   32 x 2 array like [[e_bin_0_low, ebin_0_up], ...[]]
+            Returns
+            --------
+            transmission for the energy bins
+            
+        '''
+        base_comps = [
+            self.components[name] for name in [
+                'front_window', 'rear_window', 'dem', 'mli',
+                'calibration_foil', 'dead_layer'
+            ]
+        ]
+
+        if attenuator:
+            base_comps.append(self.components['attenuator'])
+
+        fine_grids = [10, 12, 17, 11, 18, 16]
+
+        if detector_id in fine_grids:
+            comp = Compound(base_comps + [self.components['grid_covers']])
+        else:
+            comp = Compound(base_comps)
+
+        ebins_1d = energy_bins.reshape(-1) * u.keV
+        #convert energy bin ranges to 1d
+        det_trans = comp.transmission(ebins_1d)
+        mean_trans = np.mean(det_trans.reshape((-1, 2)), axis=1)
+        #calculate mean energy transmission factors for energy bins
+        return mean_trans
+
+    def get_transmission_by_component(self):
+        """
+        Get the contributions to the total transmission by broken down by component.
+
+        Returns
+        -------
+        `dict`
+            Entries are Compounds for each component
+        """
+        return self.components
+
+    def get_transmission_by_material(self):
+        """
+        Get the contribution to the transmission by total thickness for each material.
+
+        Layers of the same materials are combined to return one instance with the total thickness.
+
+        Returns
+        -------
+        `dict`
+            Entries are meterials with the total thickness for that material.
+        """
+        material_thickness = dict()
+        for name, layers in COMPONENTS.items():
+            for material_name, thickness in layers:
+                if material_name == 'solarblack':
+                    material_name = self.solarblack
+                if material_name in material_thickness.keys():
+                    material_thickness[material_name] += thickness.to('mm')
+                else:
+                    material_thickness[material_name] = thickness.to('mm')
+        res = {}
+        for name, thickness in material_thickness.items():
+            frac_mass, density = self.materials[name]
+            mat = self.create_material(name=name,
+                                       fractional_masses=frac_mass,
+                                       density=density,
+                                       thickness=thickness)
+            res[name] = mat
+
+        return res
+
+    @classmethod
+    def create_material(cls,
+                        name=None,
+                        fractional_masses=None,
+                        thickness=None,
+                        density=None):
+        """
+        Create a new material given the composition and fractional masses.
+
+        Parameters
+        ----------
+        name : `str`
+            Name of the meterial
+        fractional_masses : `dict`
+            The element and fractional masses of the material e.g. `{'H': 0.031, 'O': 0.969}`
+        thickness : `astropy.units.Quantity`
+            Thickness of the material
+        density : `astropy.units.Quantity`
+            Density of the material
+
+        Returns
+        -------
+        `roentgen.absorption.material.Material`
+            The material
+        """
+        material = Material('h', thickness, density)
+        material.name = name
+        # probably don't need this
+        material.density = density
+
+        # TODO remove in favour of upstream fix when completed
+        #  see https://github.com/ehsteve/roentgen/issues/26
+        def func(composition, e):
+            return sum([
+                MassAttenuationCoefficient(element).func(e) * frac_mass
+                for element, frac_mass in composition.items()
+            ])
+
+        material_func = partial(func, fractional_masses)
+
+        material.mass_attenuation_coefficient.func = material_func
+        return material
+
+
+"""
+def generate_transmission_tables():
+    from datetime import datetime
+    cur_date = datetime.now().strftime('%Y%m%d')
+    datetime.now().strftime('%Y%m%d')
+    trans = Transmission()
+    norm_sci_energies = trans.get_transmission()
+    norm_sci_energies.write(f'stix_transmission_sci_energies_{cur_date}.csv')
+    norm_high_res = trans.get_transmission(energies=energies)
+    norm_high_res.write(f'stix_transmission_highres_{cur_date}.csv')
+
+    comps = trans.get_transmission_by_component()
+
+    comps_sci_energies = Table([c.transmission(trans.energies) for c in comps.values()],
+                               names=[k for k in comps.keys()])
+    comps_sci_energies['energy'] = trans.energies
+    comps_sci_energies.write(f'stix_transmission_by_component_sci_energies_{cur_date}.csv')
+
+    comps_highres = Table([c.transmission(energies) for c in comps.values()],
+                          names=[k for k in comps.keys()])
+    comps_highres['energy'] = energies
+    comps_highres.write(f'stix_transmission_by_component_highres_{cur_date}.csv')
+
+generate_transmission_tables()
+"""
+
+
+def get_detector_absorption(energies=None):
+    mass_fraction = {'Te': 0.531644, 'Cd': 0.4683554}
+    desity = 5.85 * u.g / u.cm**3
+    thickness = 1 * u.mm
+    material = Transmission.create_material(name='cdte',
+                                            fractional_masses=mass_fraction,
+                                            thickness=thickness,
+                                            density=density)
+    if energies is None:
+        energies = np.linspace(2, 150, 1001)
+        energies = energies * u.keV
+    absorption = material.absorption(energies)
+    print(absorption)
+
+
+#def get_transmission(energies):
+#    return trans.get_transmission(energies)
+if __name__ == '__main__':
+    energies = np.linspace(2, 150, 1001)
+    tr = Transmission()
+    t = tr.get_transmission(energies)
+    t.pprint()
+    print(t['det-0'][0])
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class Transmission +(solarblack='solarblack_carbon') +
+
+

Calculate the energy dependant transmission of X-ray through the instrument

+

Create a new instance of the transmission with the given solar black composition.

+

Parameters

+
+
solarblack : str</code> optional
+
The SolarBlack composition to use.
+
+
+ +Expand source code + +
class Transmission:
+    """
+    Calculate the energy dependant transmission of X-ray through the instrument
+    """
+    def __init__(self, solarblack='solarblack_carbon'):
+        """
+        Create a new instance of the transmission with the given solar black composition.
+
+        Parameters
+        ----------
+
+        solarblack : `str` optional
+            The SolarBlack composition to use.
+        """
+        if solarblack not in ['solarblack_oxygen', 'solarblack_carbon']:
+            raise ValueError(
+                "solarblack must be either 'solarblack_oxygen' or "
+                "'solarblack_carbon'.")
+
+        self.solarblack = solarblack
+        self.materials = MATERIALS
+        self.components = COMPONENTS
+        self.components = dict()
+
+        for name, layers in COMPONENTS.items():
+            parts = []
+            for material, thickness in layers:
+                if material == 'solarblack':
+                    material = self.solarblack
+                mass_frac, den = MATERIALS[material]
+                if material == 'al':
+                    thickness = thickness * 0.8
+                parts.append(
+                    self.create_material(name=material,
+                                         fractional_masses=mass_frac,
+                                         thickness=thickness,
+                                         density=den))
+            self.components[name] = Compound(parts)
+
+    def get_transmission(self, energies, attenuator=False):
+        """
+        Get the transmission for each detector at the center of the given energy bins.
+
+        If energies are not supplied will evaluate at standard science energy channels
+
+        Parameters
+        ----------
+        energies : `astropy.units.Quantity`, optional
+            The energies to evaluate the transmission
+        attenuator : `bool`, optional
+            True for attenuator in X-ray path, False for attenuator not in X-ray path
+
+        Returns
+        -------
+        `astropy.table.Table`
+            Table containing the transmission values for each energy and detector
+        """
+        base_comps = [
+            self.components[name] for name in [
+                'front_window', 'rear_window', 'dem', 'mli',
+                'calibration_foil', 'dead_layer'
+            ]
+        ]
+
+        #if energies is None:
+        energies = energies * u.keV
+        #    self.energies = [ENERGY_CHANNELS[i].e_lower for i in range(1, 32)] * u.keV
+
+        if attenuator:
+            base_comps.append(self.components['attenuator'])
+
+        base = Compound(base_comps)
+        base_trans = base.transmission(energies)
+
+        fine = Compound(base_comps + [self.components['grid_covers']])
+        fine_trans = fine.transmission(energies)
+
+        # TODO need to move to configuration db
+        fine_grids = np.array([11, 13, 18, 12, 19, 17]) - 1
+        detector_transmission = Table()
+        # transmission['sci_channel'] = range(1, 31)
+        detector_transmission['energies'] = energies
+        for i in range(32):
+            name = f'det-{i}'
+            if np.isin(i, fine_grids):
+                detector_transmission[name] = fine_trans
+            else:
+                detector_transmission[name] = base_trans
+        return detector_transmission
+
+    def get_detector_transmission(self,
+                                  detector_id,
+                                  energy_bins,
+                                  attenuator=False):
+        '''
+            get transmission for detector
+            Arguments
+            ---------
+            detector:  ranges from 0...31 
+            energy_bins:   32 x 2 array like [[e_bin_0_low, ebin_0_up], ...[]]
+            Returns
+            --------
+            transmission for the energy bins
+            
+        '''
+        base_comps = [
+            self.components[name] for name in [
+                'front_window', 'rear_window', 'dem', 'mli',
+                'calibration_foil', 'dead_layer'
+            ]
+        ]
+
+        if attenuator:
+            base_comps.append(self.components['attenuator'])
+
+        fine_grids = [10, 12, 17, 11, 18, 16]
+
+        if detector_id in fine_grids:
+            comp = Compound(base_comps + [self.components['grid_covers']])
+        else:
+            comp = Compound(base_comps)
+
+        ebins_1d = energy_bins.reshape(-1) * u.keV
+        #convert energy bin ranges to 1d
+        det_trans = comp.transmission(ebins_1d)
+        mean_trans = np.mean(det_trans.reshape((-1, 2)), axis=1)
+        #calculate mean energy transmission factors for energy bins
+        return mean_trans
+
+    def get_transmission_by_component(self):
+        """
+        Get the contributions to the total transmission by broken down by component.
+
+        Returns
+        -------
+        `dict`
+            Entries are Compounds for each component
+        """
+        return self.components
+
+    def get_transmission_by_material(self):
+        """
+        Get the contribution to the transmission by total thickness for each material.
+
+        Layers of the same materials are combined to return one instance with the total thickness.
+
+        Returns
+        -------
+        `dict`
+            Entries are meterials with the total thickness for that material.
+        """
+        material_thickness = dict()
+        for name, layers in COMPONENTS.items():
+            for material_name, thickness in layers:
+                if material_name == 'solarblack':
+                    material_name = self.solarblack
+                if material_name in material_thickness.keys():
+                    material_thickness[material_name] += thickness.to('mm')
+                else:
+                    material_thickness[material_name] = thickness.to('mm')
+        res = {}
+        for name, thickness in material_thickness.items():
+            frac_mass, density = self.materials[name]
+            mat = self.create_material(name=name,
+                                       fractional_masses=frac_mass,
+                                       density=density,
+                                       thickness=thickness)
+            res[name] = mat
+
+        return res
+
+    @classmethod
+    def create_material(cls,
+                        name=None,
+                        fractional_masses=None,
+                        thickness=None,
+                        density=None):
+        """
+        Create a new material given the composition and fractional masses.
+
+        Parameters
+        ----------
+        name : `str`
+            Name of the meterial
+        fractional_masses : `dict`
+            The element and fractional masses of the material e.g. `{'H': 0.031, 'O': 0.969}`
+        thickness : `astropy.units.Quantity`
+            Thickness of the material
+        density : `astropy.units.Quantity`
+            Density of the material
+
+        Returns
+        -------
+        `roentgen.absorption.material.Material`
+            The material
+        """
+        material = Material('h', thickness, density)
+        material.name = name
+        # probably don't need this
+        material.density = density
+
+        # TODO remove in favour of upstream fix when completed
+        #  see https://github.com/ehsteve/roentgen/issues/26
+        def func(composition, e):
+            return sum([
+                MassAttenuationCoefficient(element).func(e) * frac_mass
+                for element, frac_mass in composition.items()
+            ])
+
+        material_func = partial(func, fractional_masses)
+
+        material.mass_attenuation_coefficient.func = material_func
+        return material
+
+

Static methods

+
+
+def create_material(name=None, fractional_masses=None, thickness=None, density=None) +
+
+

Create a new material given the composition and fractional masses.

+

Parameters

+
+
name : str
+
Name of the meterial
+
fractional_masses : dict
+
The element and fractional masses of the material e.g. {'H': 0.031, 'O': 0.969}
+
thickness : astropy.units.Quantity
+
Thickness of the material
+
density : astropy.units.Quantity
+
Density of the material
+
+

Returns

+

roentgen.absorption.material.Material +The material

+
+ +Expand source code + +
@classmethod
+def create_material(cls,
+                    name=None,
+                    fractional_masses=None,
+                    thickness=None,
+                    density=None):
+    """
+    Create a new material given the composition and fractional masses.
+
+    Parameters
+    ----------
+    name : `str`
+        Name of the meterial
+    fractional_masses : `dict`
+        The element and fractional masses of the material e.g. `{'H': 0.031, 'O': 0.969}`
+    thickness : `astropy.units.Quantity`
+        Thickness of the material
+    density : `astropy.units.Quantity`
+        Density of the material
+
+    Returns
+    -------
+    `roentgen.absorption.material.Material`
+        The material
+    """
+    material = Material('h', thickness, density)
+    material.name = name
+    # probably don't need this
+    material.density = density
+
+    # TODO remove in favour of upstream fix when completed
+    #  see https://github.com/ehsteve/roentgen/issues/26
+    def func(composition, e):
+        return sum([
+            MassAttenuationCoefficient(element).func(e) * frac_mass
+            for element, frac_mass in composition.items()
+        ])
+
+    material_func = partial(func, fractional_masses)
+
+    material.mass_attenuation_coefficient.func = material_func
+    return material
+
+
+
+

Methods

+
+
+def get_detector_transmission(self, detector_id, energy_bins, attenuator=False) +
+
+

get transmission for detector +Arguments

+
+
+
detector :  ranges from 0…31
+
 
+
energy_bins :  +32 x 2 array like [[e_bin_0_low, ebin_0_up], …[]]
+
 
+
+

Returns

+
+
transmission for the energy bins
+
 
+
+
+ +Expand source code + +
def get_detector_transmission(self,
+                              detector_id,
+                              energy_bins,
+                              attenuator=False):
+    '''
+        get transmission for detector
+        Arguments
+        ---------
+        detector:  ranges from 0...31 
+        energy_bins:   32 x 2 array like [[e_bin_0_low, ebin_0_up], ...[]]
+        Returns
+        --------
+        transmission for the energy bins
+        
+    '''
+    base_comps = [
+        self.components[name] for name in [
+            'front_window', 'rear_window', 'dem', 'mli',
+            'calibration_foil', 'dead_layer'
+        ]
+    ]
+
+    if attenuator:
+        base_comps.append(self.components['attenuator'])
+
+    fine_grids = [10, 12, 17, 11, 18, 16]
+
+    if detector_id in fine_grids:
+        comp = Compound(base_comps + [self.components['grid_covers']])
+    else:
+        comp = Compound(base_comps)
+
+    ebins_1d = energy_bins.reshape(-1) * u.keV
+    #convert energy bin ranges to 1d
+    det_trans = comp.transmission(ebins_1d)
+    mean_trans = np.mean(det_trans.reshape((-1, 2)), axis=1)
+    #calculate mean energy transmission factors for energy bins
+    return mean_trans
+
+
+
+def get_transmission(self, energies, attenuator=False) +
+
+

Get the transmission for each detector at the center of the given energy bins.

+

If energies are not supplied will evaluate at standard science energy channels

+

Parameters

+
+
energies : astropy.units.Quantity, optional
+
The energies to evaluate the transmission
+
attenuator : bool, optional
+
True for attenuator in X-ray path, False for attenuator not in X-ray path
+
+

Returns

+

astropy.table.Table +Table containing the transmission values for each energy and detector

+
+ +Expand source code + +
def get_transmission(self, energies, attenuator=False):
+    """
+    Get the transmission for each detector at the center of the given energy bins.
+
+    If energies are not supplied will evaluate at standard science energy channels
+
+    Parameters
+    ----------
+    energies : `astropy.units.Quantity`, optional
+        The energies to evaluate the transmission
+    attenuator : `bool`, optional
+        True for attenuator in X-ray path, False for attenuator not in X-ray path
+
+    Returns
+    -------
+    `astropy.table.Table`
+        Table containing the transmission values for each energy and detector
+    """
+    base_comps = [
+        self.components[name] for name in [
+            'front_window', 'rear_window', 'dem', 'mli',
+            'calibration_foil', 'dead_layer'
+        ]
+    ]
+
+    #if energies is None:
+    energies = energies * u.keV
+    #    self.energies = [ENERGY_CHANNELS[i].e_lower for i in range(1, 32)] * u.keV
+
+    if attenuator:
+        base_comps.append(self.components['attenuator'])
+
+    base = Compound(base_comps)
+    base_trans = base.transmission(energies)
+
+    fine = Compound(base_comps + [self.components['grid_covers']])
+    fine_trans = fine.transmission(energies)
+
+    # TODO need to move to configuration db
+    fine_grids = np.array([11, 13, 18, 12, 19, 17]) - 1
+    detector_transmission = Table()
+    # transmission['sci_channel'] = range(1, 31)
+    detector_transmission['energies'] = energies
+    for i in range(32):
+        name = f'det-{i}'
+        if np.isin(i, fine_grids):
+            detector_transmission[name] = fine_trans
+        else:
+            detector_transmission[name] = base_trans
+    return detector_transmission
+
+
+
+def get_transmission_by_component(self) +
+
+

Get the contributions to the total transmission by broken down by component.

+

Returns

+

dict +Entries are Compounds for each component

+
+ +Expand source code + +
def get_transmission_by_component(self):
+    """
+    Get the contributions to the total transmission by broken down by component.
+
+    Returns
+    -------
+    `dict`
+        Entries are Compounds for each component
+    """
+    return self.components
+
+
+
+def get_transmission_by_material(self) +
+
+

Get the contribution to the transmission by total thickness for each material.

+

Layers of the same materials are combined to return one instance with the total thickness.

+

Returns

+

dict +Entries are meterials with the total thickness for that material.

+
+ +Expand source code + +
def get_transmission_by_material(self):
+    """
+    Get the contribution to the transmission by total thickness for each material.
+
+    Layers of the same materials are combined to return one instance with the total thickness.
+
+    Returns
+    -------
+    `dict`
+        Entries are meterials with the total thickness for that material.
+    """
+    material_thickness = dict()
+    for name, layers in COMPONENTS.items():
+        for material_name, thickness in layers:
+            if material_name == 'solarblack':
+                material_name = self.solarblack
+            if material_name in material_thickness.keys():
+                material_thickness[material_name] += thickness.to('mm')
+            else:
+                material_thickness[material_name] = thickness.to('mm')
+    res = {}
+    for name, thickness in material_thickness.items():
+        frac_mass, density = self.materials[name]
+        mat = self.create_material(name=name,
+                                   fractional_masses=frac_mass,
+                                   density=density,
+                                   thickness=thickness)
+        res[name] = mat
+
+    return res
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/downloads/solo_L1A_stix-sci-xray-l1-2105090003_20210509T042711-20210509T044405_010270_V01.fits b/downloads/solo_L1A_stix-sci-xray-l1-2105090003_20210509T042711-20210509T044405_010270_V01.fits new file mode 100755 index 0000000000000000000000000000000000000000..9b900b7a0f5f35f734dca8e66e4ae7174c31b49a GIT binary patch literal 10071360 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%0D{J^Q?Xc#B-15 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

qgnu}izkFcLN8a)k$A&Av@<+!J3FdxS?HKo$ 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

O?1T31q4{cSAL6LSciC6Z-*sm;=iTqmxUBM< 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 I^gHnX16j~Ri~s-t literal 0 HcmV?d00001 diff --git a/stixdcpy/correction.py b/stixdcpy/correction.py index af20b01..93a1209 100755 --- a/stixdcpy/correction.py +++ b/stixdcpy/correction.py @@ -206,7 +206,7 @@ def L1_live_time_correction(cls, triggers, counts_arr, time_bins): cor_factor=0.94 live_ratio[:,det]=np.exp(- cor_factor*nin*asic_tau*1e-6)/(1+ nin*trig_tau) - return correction_factors, corrected_rates , count_rates,photons_in + return correction_factors, corrected_rates , count_rates,photons_in

=BNE*;r)syz_G<&)mCKL7d|L6gAo#r*J_|&UD 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