From 25b14bea5de21f28364c210382513c1c9b792d61 Mon Sep 17 00:00:00 2001 From: Anne Philipp <anne.philipp@univie.ac.at> Date: Sun, 23 Sep 2018 13:40:28 +0200 Subject: [PATCH] changed whole tree structure of flex_extract to have better overview --- python/README.md => README_pythondir.md | 0 documentation/FE_testing.txt | 13 - {python => for_developers}/COMMANDS | 0 .../ECMWF_FPparameter.xlsx | Bin .../ErrorDebug.ods | Bin .../FE_testing.txt | 0 {documentation => for_developers}/GUIDE.odt | Bin for_developers/SphinxDoc/Makefile | 20 + .../SphinxDoc/_build/doctrees/code.doctree | Bin 0 -> 75664 bytes .../_build/doctrees/environment.pickle | Bin 0 -> 34283 bytes .../SphinxDoc/_build/doctrees/index.doctree | Bin 0 -> 5497 bytes .../SphinxDoc/_build/html/.buildinfo | 4 + .../_build/html/_modules/Control.html | 344 + .../SphinxDoc/_build/html/_modules/Tools.html | 548 + .../SphinxDoc/_build/html/_modules/index.html | 87 + .../_build/html/_sources/code.rst.txt | 8 + .../_build/html/_sources/index.rst.txt | 20 + .../_build/html/_static/ajax-loader.gif | Bin 0 -> 673 bytes .../SphinxDoc/_build/html/_static/basic.css | 643 + .../SphinxDoc/_build/html/_static/classic.css | 261 + .../_build/html/_static/comment-bright.png | Bin 0 -> 756 bytes .../_build/html/_static/comment-close.png | Bin 0 -> 829 bytes .../SphinxDoc/_build/html/_static/comment.png | Bin 0 -> 641 bytes .../SphinxDoc/_build/html/_static/doctools.js | 311 + .../_build/html/_static/down-pressed.png | Bin 0 -> 222 bytes .../SphinxDoc/_build/html/_static/down.png | Bin 0 -> 202 bytes .../SphinxDoc/_build/html/_static/file.png | Bin 0 -> 286 bytes .../_build/html/_static/jquery-3.1.0.js | 10074 ++++++++++++++++ .../SphinxDoc/_build/html/_static/jquery.js | 4 + .../SphinxDoc/_build/html/_static/minus.png | Bin 0 -> 90 bytes .../SphinxDoc/_build/html/_static/plus.png | Bin 0 -> 90 bytes .../_build/html/_static/pygments.css | 69 + .../_build/html/_static/searchtools.js | 761 ++ .../SphinxDoc/_build/html/_static/sidebar.js | 159 + .../_build/html/_static/underscore-1.3.1.js | 999 ++ .../_build/html/_static/underscore.js | 31 + .../_build/html/_static/up-pressed.png | Bin 0 -> 214 bytes .../SphinxDoc/_build/html/_static/up.png | Bin 0 -> 203 bytes .../_build/html/_static/websupport.js | 808 ++ .../SphinxDoc/_build/html/code.html | 415 + .../SphinxDoc/_build/html/genindex.html | 194 + .../SphinxDoc/_build/html/index.html | 111 + .../SphinxDoc/_build/html/objects.inv | Bin 0 -> 456 bytes .../SphinxDoc/_build/html/py-modindex.html | 108 + .../SphinxDoc/_build/html/search.html | 104 + .../SphinxDoc/_build/html/searchindex.js | 1 + for_developers/SphinxDoc/code.rst | 8 + for_developers/SphinxDoc/conf.py | 170 + for_developers/SphinxDoc/index.rst | 20 + for_developers/SphinxDoc/make.bat | 36 + for_developers/classes.dot | 9 + for_developers/classes.dot.png | Bin 0 -> 96730 bytes {python => for_developers}/mk_install_tar.sh | 0 .../mk_upload_tarball.sh | 0 for_developers/packages.dot | 37 + for_developers/packages.dot.png | Bin 0 -> 38473 bytes for_developers/pylintrc | 552 + python/plot_retrieved.py | 675 -- python/pythontest/.cache/v/cache/lastfailed | 4 - python/pythontest/.pytest_cache/README.md | 8 - .../.pytest_cache/v/cache/lastfailed | 3 - .../pythontest/.pytest_cache/v/cache/nodeids | 4 - .../flex_extract_v7.1/python/UioFiles.py | 178 - .../flex_extract_v7.1/python/_config.py | 85 - .../flex_extract_v7.1/python/install.py | 546 - .../test_untar/_templates/compilejob.temp | 77 - .../_templates/ecmwf_grib1_table_128 | 197 - .../test_untar/python/ControlFile.py | 534 - .../test_untar/python/ECMWF_ENV | 4 - .../test_untar/python/EcFlexpart.py | 1314 -- .../test_untar/python/GribTools.py | 318 - .../test_untar/python/MarsRetrieval.py | 419 - .../test_untar/python/_config.py | 85 - .../test_untar/python/disaggregation.py | 141 - .../test_untar/python/get_mars_data.py | 301 - .../test_untar/python/prepare_flexpart.py | 206 - .../test_untar/python/profiling.py | 72 - .../test_untar/python/submit.py | 200 - .../test_untar/python/test_suite.py | 104 - .../TestInstallTar/test_untar/python/tools.py | 531 - python/pythontest/TestUIOFiles.py | 64 - python/pythontest/testecmwfapi.py | 16 - python/test_suite.py | 104 - run/jobscripts/job.ksh | 2 +- run/mars_requests.dat | 252 - setup.sh | 4 +- .../src => source/fortran}/Makefile.CRAY | 0 .../src => source/fortran}/Makefile.gfortran | 0 .../src => source/fortran}/Makefile.ifort | 0 .../fortran}/Makefile.local.gfortran | 0 .../fortran}/Makefile.local.ifort | 0 .../src => source/fortran}/Makefile.new | 0 .../src => source/fortran}/ftrafo.f | 0 .../src => source/fortran}/grphreal.f | 0 .../src => source/fortran}/jparams.h | 0 .../src => source/fortran}/phgrreal.f | 0 .../src => source/fortran}/posnam.f | 0 .../src => source/fortran}/preconvert.f90 | 0 .../src => source/fortran}/rwGRIB2.f90 | 0 source/python/__init__.py | 14 + source/python/_config.py | 95 + .../python/classes}/ControlFile.py | 6 +- .../python/classes}/EcFlexpart.py | 33 +- .../python/classes}/GribTools.py | 0 .../python/classes}/MarsRetrieval.py | 7 +- {python => source/python/classes}/UioFiles.py | 39 +- source/python/classes/__init__.py | 14 + {python => source/python}/install.py | 56 +- source/python/mods/__init__.py | 14 + .../python/mods}/disaggregation.py | 0 .../python/mods}/get_mars_data.py | 4 +- .../python/mods}/plot_retrieved.py | 11 +- .../python/mods}/prepare_flexpart.py | 4 +- {python => source/python/mods}/profiling.py | 0 {python => source/python/mods}/tools.py | 0 {python => source/python}/submit.py | 10 +- {python => source}/pythontest/.coverage | 0 .../pythontest/TestData/CONTROL.temp | 0 .../pythontest/TestData/ECMWF_ENV | 0 .../pythontest/TestData/testfile.txt | 0 .../TestDir/FCOG__ML.20160410.40429.16424.grb | Bin .../TestDir/FCOG__SL.20160410.40429.16424.grb | Bin .../TestDir/FCSH__ML.20160410.40429.16424.grb | Bin .../TestDir/FCSH__SL.20160410.40429.16424.grb | Bin .../OG_OROLSM__SL.20160410.40429.16424.grb | Bin .../FCGG__SL.20160410.40429.16424.grb | Bin .../FCOG_acc_SL.20160409.40429.16424.grb | Bin .../pythontest/TestEcFlexpart.py | 32 +- {python => source}/pythontest/TestInput.py | 24 +- {python => source}/pythontest/TestInstall.py | 67 +- .../flex_extract_v7.1_ecgate/run}/ECMWF_ENV | 0 .../run/control/CONTROL.temp | 37 + .../run/control/CONTROL.temp.backup | 37 + .../run/control/CONTROL.test | 2 +- .../run/control/CONTROL.worktest | 23 +- .../run/control/CONTROL_CV | 37 + .../run/control/CONTROL_CV_PREOP | 37 + .../run/control/CONTROL_DELIA_HR | 34 + .../run/control/CONTROL_DELIA_LR | 34 + .../run/control/CONTROL_EI | 37 + .../run/control/CONTROL_ERA_HAIYAN | 34 + .../run/control/CONTROL_ERA__GLOBALETA | 37 + .../run/control/CONTROL_ERA__HIRES | 34 + .../run/control/CONTROL_FC | 31 + .../run/control/CONTROL_FC12 | 38 + .../run/control/CONTROL_HIRES | 34 + .../run/control/CONTROL_HIRESGAUSS | 34 + .../run/control/CONTROL_OD | 35 + .../run/control/CONTROL_OPS_V4.temp | 17 + .../run/control/CONTROL_OPS_V6.0 | 29 + .../run/control/CONTROL_OPS_V6.0_4V.temp | 28 + .../run/control/CONTROL_PF.temp | 38 + .../source/fortran}/Makefile.CRAY | 0 .../source/fortran}/Makefile.gfortran | 0 .../source/fortran}/Makefile.ifort | 0 .../source/fortran}/Makefile.local.gfortran | 0 .../source/fortran}/Makefile.local.ifort | 0 .../source/fortran}/Makefile.new | 0 .../source/fortran}/ftrafo.f | 0 .../source/fortran}/grphreal.f | 0 .../source/fortran}/jparams.h | 0 .../source/fortran}/phgrreal.f | 0 .../source/fortran}/posnam.f | 0 .../source/fortran}/preconvert.f90 | 0 .../source/fortran}/rwGRIB2.f90 | 0 .../source/python/__init__.py | 14 + .../source/python}/_config.py | 66 +- .../source/python/classes}/ControlFile.py | 130 +- .../source/python/classes}/EcFlexpart.py | 256 +- .../source/python/classes}/GribTools.py | 8 +- .../source/python/classes}/MarsRetrieval.py | 28 +- .../source/python/classes}/UioFiles.py | 39 +- .../source/python/classes/__init__.py | 14 + .../source}/python/install.py | 121 +- .../source/python/mods/__init__.py | 14 + .../source/python/mods}/disaggregation.py | 0 .../source/python/mods}/get_mars_data.py | 30 +- .../source/python/mods}/plot_retrieved.py | 11 +- .../source/python/mods}/prepare_flexpart.py | 40 +- .../source/python/mods}/profiling.py | 2 +- .../source/python/mods}/tools.py | 32 +- .../source}/python/submit.py | 61 +- .../templates}/compilejob.temp | 0 .../templates}/ecmwf_grib1_table_128 | 0 .../templates}/job.temp | 6 +- {python => source}/pythontest/TestPathes.py | 2 +- {python => source}/pythontest/TestTools.py | 23 +- source/pythontest/TestUIOFiles.py | 47 + {python => source}/pythontest/__init__.py | 0 .../pythontest/leos_test_suit.py | 0 .../pythontest/leos_testsuite.json | 0 {python => source}/pythontest/pytest.ini | 0 .../pythontest}/testecmwfapi.py | 2 + src/Makefile.CRAY | 62 - src/Makefile.gfortran | 62 - src/Makefile.ifort | 61 - src/Makefile.local.gfortran | 62 - src/Makefile.local.ifort | 61 - src/Makefile.new | 61 - src/ftrafo.f | 504 - src/grphreal.f | 188 - src/jparams.h | 34 - src/phgrreal.f | 553 - src/posnam.f | 25 - src/preconvert.f90 | 807 -- src/rwGRIB2.f90 | 263 - .../_templates => templates}/compilejob.temp | 0 .../ecmwf_grib1_table_128 | 0 templates/job.temp | 76 + 209 files changed, 18419 insertions(+), 9820 deletions(-) rename python/README.md => README_pythondir.md (100%) delete mode 100644 documentation/FE_testing.txt rename {python => for_developers}/COMMANDS (100%) rename {documentation => for_developers}/ECMWF_FPparameter.xlsx (100%) rename {documentation => for_developers}/ErrorDebug.ods (100%) rename FE_testing.txt => for_developers/FE_testing.txt (100%) rename {documentation => for_developers}/GUIDE.odt (100%) create mode 100644 for_developers/SphinxDoc/Makefile create mode 100644 for_developers/SphinxDoc/_build/doctrees/code.doctree create mode 100644 for_developers/SphinxDoc/_build/doctrees/environment.pickle create mode 100644 for_developers/SphinxDoc/_build/doctrees/index.doctree create mode 100644 for_developers/SphinxDoc/_build/html/.buildinfo create mode 100644 for_developers/SphinxDoc/_build/html/_modules/Control.html create mode 100644 for_developers/SphinxDoc/_build/html/_modules/Tools.html create mode 100644 for_developers/SphinxDoc/_build/html/_modules/index.html create mode 100644 for_developers/SphinxDoc/_build/html/_sources/code.rst.txt create mode 100644 for_developers/SphinxDoc/_build/html/_sources/index.rst.txt create mode 100644 for_developers/SphinxDoc/_build/html/_static/ajax-loader.gif create mode 100644 for_developers/SphinxDoc/_build/html/_static/basic.css create mode 100644 for_developers/SphinxDoc/_build/html/_static/classic.css create mode 100644 for_developers/SphinxDoc/_build/html/_static/comment-bright.png create mode 100644 for_developers/SphinxDoc/_build/html/_static/comment-close.png create mode 100644 for_developers/SphinxDoc/_build/html/_static/comment.png create mode 100644 for_developers/SphinxDoc/_build/html/_static/doctools.js create mode 100644 for_developers/SphinxDoc/_build/html/_static/down-pressed.png create mode 100644 for_developers/SphinxDoc/_build/html/_static/down.png create mode 100644 for_developers/SphinxDoc/_build/html/_static/file.png create mode 100644 for_developers/SphinxDoc/_build/html/_static/jquery-3.1.0.js create mode 100644 for_developers/SphinxDoc/_build/html/_static/jquery.js create mode 100644 for_developers/SphinxDoc/_build/html/_static/minus.png create mode 100644 for_developers/SphinxDoc/_build/html/_static/plus.png create mode 100644 for_developers/SphinxDoc/_build/html/_static/pygments.css create mode 100644 for_developers/SphinxDoc/_build/html/_static/searchtools.js create mode 100644 for_developers/SphinxDoc/_build/html/_static/sidebar.js create mode 100644 for_developers/SphinxDoc/_build/html/_static/underscore-1.3.1.js create mode 100644 for_developers/SphinxDoc/_build/html/_static/underscore.js create mode 100644 for_developers/SphinxDoc/_build/html/_static/up-pressed.png create mode 100644 for_developers/SphinxDoc/_build/html/_static/up.png create mode 100644 for_developers/SphinxDoc/_build/html/_static/websupport.js create mode 100644 for_developers/SphinxDoc/_build/html/code.html create mode 100644 for_developers/SphinxDoc/_build/html/genindex.html create mode 100644 for_developers/SphinxDoc/_build/html/index.html create mode 100644 for_developers/SphinxDoc/_build/html/objects.inv create mode 100644 for_developers/SphinxDoc/_build/html/py-modindex.html create mode 100644 for_developers/SphinxDoc/_build/html/search.html create mode 100644 for_developers/SphinxDoc/_build/html/searchindex.js create mode 100644 for_developers/SphinxDoc/code.rst create mode 100644 for_developers/SphinxDoc/conf.py create mode 100644 for_developers/SphinxDoc/index.rst create mode 100644 for_developers/SphinxDoc/make.bat create mode 100644 for_developers/classes.dot create mode 100644 for_developers/classes.dot.png rename {python => for_developers}/mk_install_tar.sh (100%) rename mk_upload_tarball.sh => for_developers/mk_upload_tarball.sh (100%) create mode 100644 for_developers/packages.dot create mode 100644 for_developers/packages.dot.png create mode 100644 for_developers/pylintrc delete mode 100755 python/plot_retrieved.py delete mode 100644 python/pythontest/.cache/v/cache/lastfailed delete mode 100644 python/pythontest/.pytest_cache/README.md delete mode 100644 python/pythontest/.pytest_cache/v/cache/lastfailed delete mode 100644 python/pythontest/.pytest_cache/v/cache/nodeids delete mode 100644 python/pythontest/TestInstallTar/flex_extract_v7.1/python/UioFiles.py delete mode 100644 python/pythontest/TestInstallTar/flex_extract_v7.1/python/_config.py delete mode 100755 python/pythontest/TestInstallTar/flex_extract_v7.1/python/install.py delete mode 100644 python/pythontest/TestInstallTar/test_untar/_templates/compilejob.temp delete mode 100644 python/pythontest/TestInstallTar/test_untar/_templates/ecmwf_grib1_table_128 delete mode 100644 python/pythontest/TestInstallTar/test_untar/python/ControlFile.py delete mode 100644 python/pythontest/TestInstallTar/test_untar/python/ECMWF_ENV delete mode 100644 python/pythontest/TestInstallTar/test_untar/python/EcFlexpart.py delete mode 100644 python/pythontest/TestInstallTar/test_untar/python/GribTools.py delete mode 100644 python/pythontest/TestInstallTar/test_untar/python/MarsRetrieval.py delete mode 100644 python/pythontest/TestInstallTar/test_untar/python/_config.py delete mode 100644 python/pythontest/TestInstallTar/test_untar/python/disaggregation.py delete mode 100755 python/pythontest/TestInstallTar/test_untar/python/get_mars_data.py delete mode 100755 python/pythontest/TestInstallTar/test_untar/python/prepare_flexpart.py delete mode 100644 python/pythontest/TestInstallTar/test_untar/python/profiling.py delete mode 100755 python/pythontest/TestInstallTar/test_untar/python/submit.py delete mode 100755 python/pythontest/TestInstallTar/test_untar/python/test_suite.py delete mode 100644 python/pythontest/TestInstallTar/test_untar/python/tools.py delete mode 100644 python/pythontest/TestUIOFiles.py delete mode 100644 python/pythontest/testecmwfapi.py delete mode 100755 python/test_suite.py delete mode 100644 run/mars_requests.dat rename {python/pythontest/TestInstallTar/flex_extract_v7.1/src => source/fortran}/Makefile.CRAY (100%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/src => source/fortran}/Makefile.gfortran (100%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/src => source/fortran}/Makefile.ifort (100%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/src => source/fortran}/Makefile.local.gfortran (100%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/src => source/fortran}/Makefile.local.ifort (100%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/src => source/fortran}/Makefile.new (100%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/src => source/fortran}/ftrafo.f (100%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/src => source/fortran}/grphreal.f (100%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/src => source/fortran}/jparams.h (100%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/src => source/fortran}/phgrreal.f (100%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/src => source/fortran}/posnam.f (100%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/src => source/fortran}/preconvert.f90 (100%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/src => source/fortran}/rwGRIB2.f90 (100%) create mode 100644 source/python/__init__.py create mode 100644 source/python/_config.py rename {python => source/python/classes}/ControlFile.py (99%) rename {python => source/python/classes}/EcFlexpart.py (99%) rename {python => source/python/classes}/GribTools.py (100%) rename {python => source/python/classes}/MarsRetrieval.py (98%) rename {python => source/python/classes}/UioFiles.py (76%) create mode 100644 source/python/classes/__init__.py rename {python => source/python}/install.py (92%) create mode 100644 source/python/mods/__init__.py rename {python => source/python/mods}/disaggregation.py (100%) rename {python => source/python/mods}/get_mars_data.py (99%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/python => source/python/mods}/plot_retrieved.py (98%) rename {python => source/python/mods}/prepare_flexpart.py (98%) rename {python => source/python/mods}/profiling.py (100%) rename {python => source/python/mods}/tools.py (100%) rename {python => source/python}/submit.py (96%) rename {python => source}/pythontest/.coverage (100%) rename {python => source}/pythontest/TestData/CONTROL.temp (100%) rename {python => source}/pythontest/TestData/ECMWF_ENV (100%) rename {python => source}/pythontest/TestData/testfile.txt (100%) rename {python => source}/pythontest/TestDir/FCOG__ML.20160410.40429.16424.grb (100%) rename {python => source}/pythontest/TestDir/FCOG__SL.20160410.40429.16424.grb (100%) rename {python => source}/pythontest/TestDir/FCSH__ML.20160410.40429.16424.grb (100%) rename {python => source}/pythontest/TestDir/FCSH__SL.20160410.40429.16424.grb (100%) rename {python => source}/pythontest/TestDir/SubTestDir/OG_OROLSM__SL.20160410.40429.16424.grb (100%) rename {python => source}/pythontest/TestDir/SubTestDir/SubSubTestDir/FCGG__SL.20160410.40429.16424.grb (100%) rename {python => source}/pythontest/TestDir/SubTestDir2/FCOG_acc_SL.20160409.40429.16424.grb (100%) rename {python => source}/pythontest/TestEcFlexpart.py (52%) rename {python => source}/pythontest/TestInput.py (93%) rename {python => source}/pythontest/TestInstall.py (52%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/python => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run}/ECMWF_ENV (100%) create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.temp create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.temp.backup rename {python/pythontest/TestInstallTar/flex_extract_v7.1 => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate}/run/control/CONTROL.test (97%) rename python/pythontest/TestInstallTar/test_untar/run/control/CONTROL.test => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.worktest (60%) create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_CV create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_CV_PREOP create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_DELIA_HR create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_DELIA_LR create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_EI create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_ERA_HAIYAN create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_ERA__GLOBALETA create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_ERA__HIRES create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_FC create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_FC12 create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_HIRES create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_HIRESGAUSS create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OD create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OPS_V4.temp create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OPS_V6.0 create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OPS_V6.0_4V.temp create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_PF.temp rename {python/pythontest/TestInstallTar/test_untar/src => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran}/Makefile.CRAY (100%) rename {python/pythontest/TestInstallTar/test_untar/src => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran}/Makefile.gfortran (100%) rename {python/pythontest/TestInstallTar/test_untar/src => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran}/Makefile.ifort (100%) rename {python/pythontest/TestInstallTar/test_untar/src => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran}/Makefile.local.gfortran (100%) rename {python/pythontest/TestInstallTar/test_untar/src => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran}/Makefile.local.ifort (100%) rename {python/pythontest/TestInstallTar/test_untar/src => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran}/Makefile.new (100%) rename {python/pythontest/TestInstallTar/test_untar/src => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran}/ftrafo.f (100%) rename {python/pythontest/TestInstallTar/test_untar/src => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran}/grphreal.f (100%) rename {python/pythontest/TestInstallTar/test_untar/src => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran}/jparams.h (100%) rename {python/pythontest/TestInstallTar/test_untar/src => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran}/phgrreal.f (100%) rename {python/pythontest/TestInstallTar/test_untar/src => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran}/posnam.f (100%) rename {python/pythontest/TestInstallTar/test_untar/src => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran}/preconvert.f90 (100%) rename {python/pythontest/TestInstallTar/test_untar/src => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran}/rwGRIB2.f90 (100%) create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/__init__.py rename {python => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python}/_config.py (60%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/python => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes}/ControlFile.py (82%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/python => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes}/EcFlexpart.py (90%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/python => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes}/GribTools.py (98%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/python => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes}/MarsRetrieval.py (95%) rename {python/pythontest/TestInstallTar/test_untar/python => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes}/UioFiles.py (76%) create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/__init__.py rename {python/pythontest/TestInstallTar/test_untar => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source}/python/install.py (82%) create mode 100644 source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/__init__.py rename {python/pythontest/TestInstallTar/flex_extract_v7.1/python => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods}/disaggregation.py (100%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/python => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods}/get_mars_data.py (92%) rename {python/pythontest/TestInstallTar/test_untar/python => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods}/plot_retrieved.py (98%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/python => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods}/prepare_flexpart.py (86%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/python => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods}/profiling.py (96%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/python => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods}/tools.py (95%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1 => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source}/python/submit.py (77%) rename {_templates => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/templates}/compilejob.temp (100%) rename {_templates => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/templates}/ecmwf_grib1_table_128 (100%) rename {_templates => source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/templates}/job.temp (91%) rename {python => source}/pythontest/TestPathes.py (93%) rename {python => source}/pythontest/TestTools.py (92%) create mode 100644 source/pythontest/TestUIOFiles.py rename {python => source}/pythontest/__init__.py (100%) rename python/pythontest/TestInstallTar/flex_extract_v7.1/python/test_suite.py => source/pythontest/leos_test_suit.py (100%) rename python/testsuite.json => source/pythontest/leos_testsuite.json (100%) rename {python => source}/pythontest/pytest.ini (100%) rename {python/pythontest/TestInstallTar/test_untar/python => source/pythontest}/testecmwfapi.py (93%) delete mode 100644 src/Makefile.CRAY delete mode 100644 src/Makefile.gfortran delete mode 100644 src/Makefile.ifort delete mode 100644 src/Makefile.local.gfortran delete mode 100644 src/Makefile.local.ifort delete mode 100644 src/Makefile.new delete mode 100644 src/ftrafo.f delete mode 100644 src/grphreal.f delete mode 100644 src/jparams.h delete mode 100644 src/phgrreal.f delete mode 100644 src/posnam.f delete mode 100644 src/preconvert.f90 delete mode 100644 src/rwGRIB2.f90 rename {python/pythontest/TestInstallTar/flex_extract_v7.1/_templates => templates}/compilejob.temp (100%) rename {python/pythontest/TestInstallTar/flex_extract_v7.1/_templates => templates}/ecmwf_grib1_table_128 (100%) create mode 100644 templates/job.temp diff --git a/python/README.md b/README_pythondir.md similarity index 100% rename from python/README.md rename to README_pythondir.md diff --git a/documentation/FE_testing.txt b/documentation/FE_testing.txt deleted file mode 100644 index 7ea1882..0000000 --- a/documentation/FE_testing.txt +++ /dev/null @@ -1,13 +0,0 @@ -Abhängigkeiten: -pytest -pytest-cov (https://pypi.org/project/pytest-cov/ ; https://pytest-cov.readthedocs.io/en/latest/) -coverage - -#Grundsätzlicher Befehl die Coverage des Testens zu überprüfen -pytest --cov=PATH_TO_PROJECT_SRC PATH_TO_TEST_SRC - -# einen test mit einem bestimmten marker nicht ausführen -pytest TestTools.py -m "not msuser_pw" - -# Tests mit einem bestimmten Marker ausführen -pytest TestTools.py -m "msuser_pw" \ No newline at end of file diff --git a/python/COMMANDS b/for_developers/COMMANDS similarity index 100% rename from python/COMMANDS rename to for_developers/COMMANDS diff --git a/documentation/ECMWF_FPparameter.xlsx b/for_developers/ECMWF_FPparameter.xlsx similarity index 100% rename from documentation/ECMWF_FPparameter.xlsx rename to for_developers/ECMWF_FPparameter.xlsx diff --git a/documentation/ErrorDebug.ods b/for_developers/ErrorDebug.ods similarity index 100% rename from documentation/ErrorDebug.ods rename to for_developers/ErrorDebug.ods diff --git a/FE_testing.txt b/for_developers/FE_testing.txt similarity index 100% rename from FE_testing.txt rename to for_developers/FE_testing.txt diff --git a/documentation/GUIDE.odt b/for_developers/GUIDE.odt similarity index 100% rename from documentation/GUIDE.odt rename to for_developers/GUIDE.odt diff --git a/for_developers/SphinxDoc/Makefile b/for_developers/SphinxDoc/Makefile new file mode 100644 index 0000000..8cf141e --- /dev/null +++ b/for_developers/SphinxDoc/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = flex_extract_test +SOURCEDIR = . +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) \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/doctrees/code.doctree b/for_developers/SphinxDoc/_build/doctrees/code.doctree new file mode 100644 index 0000000000000000000000000000000000000000..56483ec1f551a203c6a9bd2860a9a16a75aa90e2 GIT binary patch literal 75664 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 literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/doctrees/environment.pickle b/for_developers/SphinxDoc/_build/doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..f5747e8d08245e5f0d713000761e4dda42e12664 GIT binary patch literal 34283 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	$cQDl{SRl670qOb71xfLN^z>Yk<~Ru+S{izcPQ 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⪙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 HN|W>emqG<m literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/doctrees/index.doctree b/for_developers/SphinxDoc/_build/doctrees/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..bc7865e3eaa936bb08c66074da4766ff426b928a GIT binary patch literal 5497 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 No2Spnz)+f`2LL97kw*Xk literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/html/.buildinfo b/for_developers/SphinxDoc/_build/html/.buildinfo new file mode 100644 index 0000000..6ecb8f8 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 212b568e87f0f003f33f9f448d70fca8 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/for_developers/SphinxDoc/_build/html/_modules/Control.html b/for_developers/SphinxDoc/_build/html/_modules/Control.html new file mode 100644 index 0000000..58cd8f5 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_modules/Control.html @@ -0,0 +1,344 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Control — flex_extract_test 7.1 documentation</title> + <link rel="stylesheet" href="../_static/classic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '7.1', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + </head> + <body> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="../py-modindex.html" title="Python Module Index" + >modules</a> |</li> + <li class="nav-item nav-item-0"><a href="../index.html">flex_extract_test 7.1 documentation</a> »</li> + <li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Module code</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body" role="main"> + + <h1>Source code for Control</h1><div class="highlight"><pre> +<span></span><span class="ch">#!/usr/bin/env python</span> +<span class="c1"># -*- coding: utf-8 -*-</span> +<span class="c1">#************************************************************************</span> +<span class="c1"># TODO AP</span> +<span class="c1"># - write a test class</span> +<span class="c1"># - check documentation</span> +<span class="c1">#************************************************************************</span> +<span class="sd">"""</span> +<span class="sd">@Author: Leopold Haimberger (University of Vienna)</span> + +<span class="sd">@Date: November 2015</span> + +<span class="sd">@ChangeHistory:</span> +<span class="sd"> February 2018 - Anne Philipp (University of Vienna):</span> +<span class="sd"> - applied PEP8 style guide</span> +<span class="sd"> - added documentation</span> +<span class="sd"> - applied some minor modifications in programming style/structure</span> +<span class="sd"> - moved Control class in a file for its own</span> + +<span class="sd">@License:</span> +<span class="sd"> (C) Copyright 2015-2018.</span> + +<span class="sd"> This software is licensed under the terms of the Apache Licence Version 2.0</span> +<span class="sd"> which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.</span> + +<span class="sd">@Requirements:</span> +<span class="sd"> A standard python 2.6 or 2.7 installation</span> + +<span class="sd">@Description:</span> +<span class="sd"> The Control files are the steering part of the FLEXPART extraction</span> +<span class="sd"> software. All necessary parameters needed to retrieve the data fields</span> +<span class="sd"> from the MARS archive for driving FLEXPART are set in a Control file.</span> +<span class="sd"> Some specific parameters like the start and end dates can be overwritten</span> +<span class="sd"> by the command line parameters, but in generel all parameters needed</span> +<span class="sd"> for a complete set of fields for FLEXPART can be set in the Control files.</span> + +<span class="sd">"""</span> +<span class="c1"># ------------------------------------------------------------------------------</span> +<span class="c1"># MODULES</span> +<span class="c1"># ------------------------------------------------------------------------------</span> +<span class="kn">import</span> <span class="nn">os</span> +<span class="kn">import</span> <span class="nn">inspect</span> +<span class="kn">import</span> <span class="nn">Tools</span> +<span class="c1"># ------------------------------------------------------------------------------</span> +<span class="c1"># CLASS</span> +<span class="c1"># ------------------------------------------------------------------------------</span> +<span class="k">class</span> <span class="nc">Control</span><span class="p">:</span> + <span class="sd">'''</span> +<span class="sd"> Class containing the information of the ECMWFDATA control file.</span> + +<span class="sd"> Contains all the parameters of control files, which are e.g.:</span> +<span class="sd"> DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME,</span> +<span class="sd"> STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT,</span> +<span class="sd"> LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY,</span> +<span class="sd"> OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT,</span> +<span class="sd"> ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR,</span> +<span class="sd"> MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR,</span> +<span class="sd"> BASETIME, DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS</span> + +<span class="sd"> For more information about format and content of the parameter</span> +<span class="sd"> see documentation.</span> + +<span class="sd"> '''</span> + + <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span> + <span class="sd">'''</span> +<span class="sd"> @Description:</span> +<span class="sd"> Initialises the instance of Control class and defines and</span> +<span class="sd"> assign all controlfile variables. Set default values if</span> +<span class="sd"> parameter was not in CONTROL file.</span> + +<span class="sd"> @Input:</span> +<span class="sd"> self: instance of Control class</span> +<span class="sd"> Description see class documentation.</span> + +<span class="sd"> filename: string</span> +<span class="sd"> Name of control file.</span> + +<span class="sd"> @Return:</span> +<span class="sd"> <nothing></span> +<span class="sd"> '''</span> + + <span class="c1"># read whole CONTROL file</span> + <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span> + <span class="n">fdata</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'</span><span class="se">\n</span><span class="s1">'</span><span class="p">)</span> + + <span class="c1"># go through every line and store parameter</span> + <span class="c1"># as class variable</span> + <span class="k">for</span> <span class="n">ldata</span> <span class="ow">in</span> <span class="n">fdata</span><span class="p">:</span> + <span class="n">data</span> <span class="o">=</span> <span class="n">ldata</span><span class="o">.</span><span class="n">split</span><span class="p">()</span> + <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="o">></span> <span class="mi">1</span><span class="p">:</span> + <span class="k">if</span> <span class="s1">'m_'</span> <span class="ow">in</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">():</span> + <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">2</span><span class="p">:]</span> + <span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s1">'class'</span><span class="p">:</span> + <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'marsclass'</span> + <span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s1">'day1'</span><span class="p">:</span> + <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'start_date'</span> + <span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s1">'day2'</span><span class="p">:</span> + <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'end_date'</span> + <span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s1">'addpar'</span><span class="p">:</span> + <span class="k">if</span> <span class="s1">'/'</span> <span class="ow">in</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span> + <span class="c1"># remove leading '/' sign from addpar content</span> + <span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'/'</span><span class="p">:</span> + <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">1</span><span class="p">:]</span> + <span class="n">dd</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span> + <span class="n">data</span> <span class="o">=</span> <span class="p">[</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span> + <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">dd</span><span class="p">:</span> + <span class="n">data</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> + <span class="k">pass</span> + <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span> + <span class="k">if</span> <span class="s1">'$'</span> <span class="ow">in</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span> + <span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">(),</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> + <span class="k">while</span> <span class="s1">'$'</span> <span class="ow">in</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span> + <span class="n">i</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="s1">'$'</span><span class="p">)</span> + <span class="n">j</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s1">'{'</span><span class="p">)</span> + <span class="n">k</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s1">'}'</span><span class="p">)</span> + <span class="n">var</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">:</span><span class="n">k</span><span class="p">])</span> + <span class="k">if</span> <span class="n">var</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">][:</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">var</span> <span class="o">+</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">k</span><span class="o">+</span><span class="mi">1</span><span class="p">:]</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">Tools</span><span class="o">.</span><span class="n">myerror</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> + <span class="s1">'Could not find variable '</span> <span class="o">+</span> + <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">:</span><span class="n">k</span><span class="p">]</span> <span class="o">+</span> + <span class="s1">' while reading '</span> <span class="o">+</span> + <span class="n">filename</span><span class="p">)</span> + <span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">+</span> <span class="s1">'_expanded'</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> + <span class="k">else</span><span class="p">:</span> + <span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">!=</span> <span class="s1">'none'</span><span class="p">:</span> + <span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">(),</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> + <span class="k">else</span><span class="p">:</span> + <span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">(),</span> <span class="kc">None</span><span class="p">)</span> + <span class="k">elif</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="o">></span> <span class="mi">2</span><span class="p">:</span> + <span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">(),</span> <span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">:]))</span> + <span class="k">else</span><span class="p">:</span> + <span class="k">pass</span> + + <span class="c1"># check a couple of necessary attributes if they contain values</span> + <span class="c1"># otherwise set default values</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'start_date'</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">start_date</span> <span class="o">=</span> <span class="kc">None</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'end_date'</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">end_date</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">start_date</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'accuracy'</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">accuracy</span> <span class="o">=</span> <span class="mi">24</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'omega'</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">omega</span> <span class="o">=</span> <span class="s1">'0'</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'cwc'</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">cwc</span> <span class="o">=</span> <span class="s1">'0'</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'omegadiff'</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">omegadiff</span> <span class="o">=</span> <span class="s1">'0'</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'etadiff'</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">etadiff</span> <span class="o">=</span> <span class="s1">'0'</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'levelist'</span><span class="p">):</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'level'</span><span class="p">):</span> + <span class="nb">print</span> <span class="s1">'Warning: neither levelist nor level </span><span class="se">\</span> +<span class="s1"> specified in CONTROL file'</span> + <span class="k">else</span><span class="p">:</span> + <span class="bp">self</span><span class="o">.</span><span class="n">levelist</span> <span class="o">=</span> <span class="s1">'1/to/'</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">level</span> + <span class="k">else</span><span class="p">:</span> + <span class="k">if</span> <span class="s1">'to'</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">levelist</span><span class="p">:</span> + <span class="bp">self</span><span class="o">.</span><span class="n">level</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">levelist</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)[</span><span class="mi">2</span><span class="p">]</span> + <span class="k">else</span><span class="p">:</span> + <span class="bp">self</span><span class="o">.</span><span class="n">level</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">levelist</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> + + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'maxstep'</span><span class="p">):</span> + <span class="c1"># find out maximum step</span> + <span class="bp">self</span><span class="o">.</span><span class="n">maxstep</span> <span class="o">=</span> <span class="mi">0</span> + <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">step</span><span class="p">:</span> + <span class="k">if</span> <span class="nb">int</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">></span> <span class="bp">self</span><span class="o">.</span><span class="n">maxstep</span><span class="p">:</span> + <span class="bp">self</span><span class="o">.</span><span class="n">maxstep</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> + <span class="k">else</span><span class="p">:</span> + <span class="bp">self</span><span class="o">.</span><span class="n">maxstep</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">maxstep</span><span class="p">)</span> + + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'prefix'</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">prefix</span> <span class="o">=</span> <span class="s1">'EN'</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'makefile'</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">makefile</span> <span class="o">=</span> <span class="kc">None</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'basetime'</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">basetime</span> <span class="o">=</span> <span class="kc">None</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'date_chunk'</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">date_chunk</span> <span class="o">=</span> <span class="s1">'3'</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'grib2flexpart'</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">grib2flexpart</span> <span class="o">=</span> <span class="s1">'0'</span> + + <span class="c1"># script directory</span> + <span class="bp">self</span><span class="o">.</span><span class="n">ecmwfdatadir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">inspect</span><span class="o">.</span><span class="n">getfile</span><span class="p">(</span> + <span class="n">inspect</span><span class="o">.</span><span class="n">currentframe</span><span class="p">())))</span> <span class="o">+</span> <span class="s1">'/../'</span> + <span class="c1"># Fortran source directory</span> + <span class="bp">self</span><span class="o">.</span><span class="n">exedir</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">ecmwfdatadir</span> <span class="o">+</span> <span class="s1">'src/'</span> + + <span class="c1"># FLEXPART directory</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'flexpart_root_scripts'</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">flexpart_root_scripts</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">ecmwfdatadir</span> + + <span class="k">return</span> + + <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="sd">'''</span> +<span class="sd"> @Description:</span> +<span class="sd"> Prepares a single string with all the comma seperated Control</span> +<span class="sd"> class attributes including their values.</span> + +<span class="sd"> Example:</span> +<span class="sd"> {'kids': 0, 'name': 'Dog', 'color': 'Spotted',</span> +<span class="sd"> 'age': 10, 'legs': 2, 'smell': 'Alot'}</span> + +<span class="sd"> @Input:</span> +<span class="sd"> self: instance of Control class</span> +<span class="sd"> Description see class documentation.</span> + +<span class="sd"> @Return:</span> +<span class="sd"> string of Control class attributes with their values</span> +<span class="sd"> '''</span> + + <span class="n">attrs</span> <span class="o">=</span> <span class="nb">vars</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> + + <span class="k">return</span> <span class="s1">', '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">"</span><span class="si">%s</span><span class="s2">: </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">item</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">attrs</span><span class="o">.</span><span class="n">items</span><span class="p">())</span> + + <span class="k">def</span> <span class="nf">tolist</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="sd">'''</span> +<span class="sd"> @Description:</span> +<span class="sd"> Just generates a list of strings containing the attributes and</span> +<span class="sd"> assigned values except the attributes "_expanded", "exedir",</span> +<span class="sd"> "ecmwfdatadir" and "flexpart_root_scripts".</span> + +<span class="sd"> @Input:</span> +<span class="sd"> self: instance of Control class</span> +<span class="sd"> Description see class documentation.</span> + +<span class="sd"> @Return:</span> +<span class="sd"> l: list</span> +<span class="sd"> A sorted list of the all Control class attributes with</span> +<span class="sd"> their values except the attributes "_expanded", "exedir",</span> +<span class="sd"> "ecmwfdatadir" and "flexpart_root_scripts".</span> +<span class="sd"> '''</span> + <span class="n">attrs</span> <span class="o">=</span> <span class="nb">vars</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> + <span class="n">l</span> <span class="o">=</span> <span class="nb">list</span><span class="p">()</span> + <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">attrs</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> + <span class="k">if</span> <span class="s1">'_expanded'</span> <span class="ow">in</span> <span class="n">item</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span> + <span class="k">pass</span> + <span class="k">elif</span> <span class="s1">'exedir'</span> <span class="ow">in</span> <span class="n">item</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span> + <span class="k">pass</span> + <span class="k">elif</span> <span class="s1">'flexpart_root_scripts'</span> <span class="ow">in</span> <span class="n">item</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span> + <span class="k">pass</span> + <span class="k">elif</span> <span class="s1">'ecmwfdatadir'</span> <span class="ow">in</span> <span class="n">item</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span> + <span class="k">pass</span> + <span class="k">else</span><span class="p">:</span> + <span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">item</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="ow">is</span> <span class="nb">list</span><span class="p">:</span> + <span class="n">stot</span> <span class="o">=</span> <span class="s1">''</span> + <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">item</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span> + <span class="n">stot</span> <span class="o">+=</span> <span class="n">s</span> <span class="o">+</span> <span class="s1">' '</span> + + <span class="n">l</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">"</span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">item</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">stot</span><span class="p">))</span> + <span class="k">else</span><span class="p">:</span> +<span class="c1">#AP syntax error with doubled %s ???</span> + <span class="n">l</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">"</span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">item</span><span class="p">)</span> + <span class="k">return</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">l</span><span class="p">)</span> +</pre></div> + + </div> + </div> + </div> + <div class="sphinxsidebar" role="navigation" aria-label="main navigation"> + <div class="sphinxsidebarwrapper"> +<div id="searchbox" style="display: none" role="search"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <div><input type="text" name="q" /></div> + <div><input type="submit" value="Go" /></div> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + >index</a></li> + <li class="right" > + <a href="../py-modindex.html" title="Python Module Index" + >modules</a> |</li> + <li class="nav-item nav-item-0"><a href="../index.html">flex_extract_test 7.1 documentation</a> »</li> + <li class="nav-item nav-item-1"><a href="index.html" >Module code</a> »</li> + </ul> + </div> + <div class="footer" role="contentinfo"> + © Copyright 2018, AP. + Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6. + </div> + </body> +</html> \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/html/_modules/Tools.html b/for_developers/SphinxDoc/_build/html/_modules/Tools.html new file mode 100644 index 0000000..1ed9b76 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_modules/Tools.html @@ -0,0 +1,548 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Tools — flex_extract_test 7.1 documentation</title> + <link rel="stylesheet" href="../_static/classic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '7.1', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + </head> + <body> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="../py-modindex.html" title="Python Module Index" + >modules</a> |</li> + <li class="nav-item nav-item-0"><a href="../index.html">flex_extract_test 7.1 documentation</a> »</li> + <li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Module code</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body" role="main"> + + <h1>Source code for Tools</h1><div class="highlight"><pre> +<span></span><span class="ch">#!/usr/bin/env python</span> +<span class="c1"># -*- coding: utf-8 -*-</span> +<span class="c1">#************************************************************************</span> +<span class="c1"># TODO AP</span> +<span class="c1">#AP</span> +<span class="c1"># -</span> +<span class="c1">#************************************************************************</span> +<span class="sd">"""</span> + +<span class="sd">"""</span> +<span class="c1"># ------------------------------------------------------------------------------</span> +<span class="c1"># MODULES</span> +<span class="c1"># ------------------------------------------------------------------------------</span> +<span class="kn">from</span> <span class="nn">argparse</span> <span class="k">import</span> <span class="n">ArgumentParser</span><span class="p">,</span> <span class="n">ArgumentDefaultsHelpFormatter</span> +<span class="kn">import</span> <span class="nn">os</span> +<span class="kn">import</span> <span class="nn">errno</span> +<span class="kn">import</span> <span class="nn">sys</span> +<span class="kn">import</span> <span class="nn">glob</span> +<span class="kn">from</span> <span class="nn">numpy</span> <span class="k">import</span> <span class="o">*</span> +<span class="kn">from</span> <span class="nn">gribapi</span> <span class="k">import</span> <span class="o">*</span> +<span class="kn">import</span> <span class="nn">Control</span> + +<span class="c1"># ------------------------------------------------------------------------------</span> +<span class="c1"># FUNCTIONS</span> +<span class="c1"># ------------------------------------------------------------------------------</span> + +<div class="viewcode-block" id="interpret_args_and_control"><a class="viewcode-back" href="../code.html#Tools.interpret_args_and_control">[docs]</a><span class="k">def</span> <span class="nf">interpret_args_and_control</span><span class="p">():</span> + <span class="sd">'''</span> +<span class="sd"> @Description:</span> +<span class="sd"> Assigns the command line arguments and reads control file</span> +<span class="sd"> content. Apply default values for non mentioned arguments.</span> + +<span class="sd"> @Input:</span> +<span class="sd"> <nothing></span> + +<span class="sd"> @Return:</span> +<span class="sd"> args: instance of ArgumentParser</span> +<span class="sd"> Contains the commandline arguments from script/program call.</span> + +<span class="sd"> c: instance of class Control</span> +<span class="sd"> Contains all necessary information of a control file. The parameters</span> +<span class="sd"> are: DAY1, DAY2, DTIME, MAXSTEP, TYPE, TIME, STEP, CLASS, STREAM,</span> +<span class="sd"> NUMBER, EXPVER, GRID, LEFT, LOWER, UPPER, RIGHT, LEVEL, LEVELIST,</span> +<span class="sd"> RESOL, GAUSS, ACCURACY, OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA,</span> +<span class="sd"> SMOOTH, FORMAT, ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS,</span> +<span class="sd"> ECFSDIR, MAILOPS, MAILFAIL, GRIB2FLEXPART, DEBUG, INPUTDIR,</span> +<span class="sd"> OUTPUTDIR, FLEXPART_ROOT_SCRIPTS</span> +<span class="sd"> For more information about format and content of the parameter see</span> +<span class="sd"> documentation.</span> + +<span class="sd"> '''</span> + <span class="n">parser</span> <span class="o">=</span> <span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s1">'Retrieve FLEXPART input from </span><span class="se">\</span> +<span class="s1"> ECMWF MARS archive'</span><span class="p">,</span> + <span class="n">formatter_class</span><span class="o">=</span><span class="n">ArgumentDefaultsHelpFormatter</span><span class="p">)</span> + + <span class="c1"># the most important arguments</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--start_date"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s2">"start_date"</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"start date YYYYMMDD"</span><span class="p">)</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--end_date"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s2">"end_date"</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"end_date YYYYMMDD"</span><span class="p">)</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--date_chunk"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s2">"date_chunk"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"# of days to be retrieved at once"</span><span class="p">)</span> + + <span class="c1"># some arguments that override the default in the control file</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--basetime"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s2">"basetime"</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"base such as 00/12 (for half day retrievals)"</span><span class="p">)</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--step"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s2">"step"</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"steps such as 00/to/48"</span><span class="p">)</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--levelist"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s2">"levelist"</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"Vertical levels to be retrieved, e.g. 30/to/60"</span><span class="p">)</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--area"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s2">"area"</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"area defined as north/west/south/east"</span><span class="p">)</span> + + <span class="c1"># set the working directories</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--inputdir"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s2">"inputdir"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"root directory for storing intermediate files"</span><span class="p">)</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--outputdir"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s2">"outputdir"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"root directory for storing output files"</span><span class="p">)</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--flexpart_root_scripts"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s2">"flexpart_root_scripts"</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"FLEXPART root directory (to find grib2flexpart </span><span class="se">\</span> +<span class="s2"> and COMMAND file)</span><span class="se">\n</span><span class="s2">\ Normally ECMWFDATA resides in </span><span class="se">\</span> +<span class="s2"> the scripts directory of the FLEXPART distribution"</span><span class="p">)</span> + + <span class="c1"># this is only used by prepareFLEXPART.py to rerun a postprocessing step</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--ppid"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s2">"ppid"</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"Specify parent process id for </span><span class="se">\</span> +<span class="s2"> rerun of prepareFLEXPART"</span><span class="p">)</span> + + <span class="c1"># arguments for job submission to ECMWF, only needed by submit.py</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--job_template"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s1">'job_template'</span><span class="p">,</span> + <span class="n">default</span><span class="o">=</span><span class="s2">"job.temp"</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"job template file for submission to ECMWF"</span><span class="p">)</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--queue"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s2">"queue"</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"queue for submission to ECMWF </span><span class="se">\</span> +<span class="s2"> (e.g. ecgate or cca )"</span><span class="p">)</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--controlfile"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s2">"controlfile"</span><span class="p">,</span> + <span class="n">default</span><span class="o">=</span><span class="s1">'CONTROL.temp'</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"file with control parameters"</span><span class="p">)</span> + <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--debug"</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s2">"debug"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> + <span class="n">help</span><span class="o">=</span><span class="s2">"Debug mode - leave temporary files intact"</span><span class="p">)</span> + + <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span> + + <span class="c1"># create instance of Control for specified controlfile</span> + <span class="c1"># and assign the parameters (and default values if necessary)</span> + <span class="k">try</span><span class="p">:</span> + <span class="n">c</span> <span class="o">=</span> <span class="n">Control</span><span class="o">.</span><span class="n">Control</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">controlfile</span><span class="p">)</span> + <span class="k">except</span> <span class="ne">IOError</span><span class="p">:</span> + <span class="k">try</span><span class="p">:</span> + <span class="n">c</span> <span class="o">=</span> <span class="n">Control</span><span class="o">.</span><span class="n">Control</span><span class="p">(</span><span class="n">localpythonpath</span> <span class="o">+</span> <span class="n">args</span><span class="o">.</span><span class="n">controlfile</span><span class="p">)</span> + <span class="k">except</span><span class="p">:</span> + <span class="nb">print</span><span class="p">(</span><span class="s1">'Could not read control file "'</span> <span class="o">+</span> <span class="n">args</span><span class="o">.</span><span class="n">controlfile</span> <span class="o">+</span> <span class="s1">'"'</span><span class="p">)</span> + <span class="nb">print</span><span class="p">(</span><span class="s1">'Either it does not exist or its syntax is wrong.'</span><span class="p">)</span> + <span class="nb">print</span><span class="p">(</span><span class="s1">'Try "'</span> <span class="o">+</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> + <span class="s1">' -h" to print usage information'</span><span class="p">)</span> + <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> + + <span class="c1"># check for having at least a starting date</span> + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">start_date</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">and</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="s1">'start_date'</span><span class="p">)</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> + <span class="nb">print</span><span class="p">(</span><span class="s1">'start_date specified neither in command line nor </span><span class="se">\</span> +<span class="s1"> in control file '</span> <span class="o">+</span> <span class="n">args</span><span class="o">.</span><span class="n">controlfile</span><span class="p">)</span> + <span class="nb">print</span><span class="p">(</span><span class="s1">'Try "'</span> <span class="o">+</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> + <span class="s1">' -h" to print usage information'</span><span class="p">)</span> + <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> + + <span class="c1"># save all existing command line parameter to the Control instance</span> + <span class="c1"># if parameter is not specified through the command line or CONTROL file</span> + <span class="c1"># set default values</span> + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">start_date</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">start_date</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">start_date</span> + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">end_date</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">end_date</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">end_date</span> + <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">end_date</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">end_date</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">start_date</span> + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">date_chunk</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">date_chunk</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">date_chunk</span> + + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="s1">'debug'</span><span class="p">):</span> + <span class="n">c</span><span class="o">.</span><span class="n">debug</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">debug</span> + + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">inputdir</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">args</span><span class="o">.</span><span class="n">outputdir</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">inputdir</span> <span class="o">=</span> <span class="s1">'../work'</span> + <span class="n">c</span><span class="o">.</span><span class="n">outputdir</span> <span class="o">=</span> <span class="s1">'../work'</span> + <span class="k">else</span><span class="p">:</span> + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">inputdir</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">inputdir</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">inputdir</span> + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">outputdir</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">outputdir</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">inputdir</span> + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">outputdir</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">outputdir</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">outputdir</span> + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">inputdir</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">inputdir</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">outputdir</span> + + <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="s1">'outputdir'</span><span class="p">)</span> <span class="ow">is</span> <span class="kc">False</span> <span class="ow">and</span> <span class="n">args</span><span class="o">.</span><span class="n">outputdir</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">outputdir</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">inputdir</span> + <span class="k">else</span><span class="p">:</span> + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">outputdir</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">outputdir</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">outputdir</span> + + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">area</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">afloat</span> <span class="o">=</span> <span class="s1">'.'</span> <span class="ow">in</span> <span class="n">args</span><span class="o">.</span><span class="n">area</span> + <span class="n">l</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">area</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span> + <span class="k">if</span> <span class="n">afloat</span><span class="p">:</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">l</span><span class="p">)):</span> + <span class="n">l</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="nb">float</span><span class="p">(</span><span class="n">l</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">))</span> + <span class="n">c</span><span class="o">.</span><span class="n">upper</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">left</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">lower</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">right</span> <span class="o">=</span> <span class="n">l</span> + + <span class="c1"># NOTE: basetime activates the ''operational mode''</span> + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">basetime</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">basetime</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">basetime</span> + + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">step</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">l</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">step</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span> + <span class="k">if</span> <span class="s1">'to'</span> <span class="ow">in</span> <span class="n">args</span><span class="o">.</span><span class="n">step</span><span class="o">.</span><span class="n">lower</span><span class="p">():</span> + <span class="k">if</span> <span class="s1">'by'</span> <span class="ow">in</span> <span class="n">args</span><span class="o">.</span><span class="n">step</span><span class="o">.</span><span class="n">lower</span><span class="p">():</span> + <span class="n">ilist</span> <span class="o">=</span> <span class="n">arange</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">l</span><span class="p">[</span><span class="mi">0</span><span class="p">]),</span> <span class="nb">int</span><span class="p">(</span><span class="n">l</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="nb">int</span><span class="p">(</span><span class="n">l</span><span class="p">[</span><span class="mi">4</span><span class="p">]))</span> + <span class="n">c</span><span class="o">.</span><span class="n">step</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'</span><span class="si">{:0>3}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">ilist</span><span class="p">]</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">myerror</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">args</span><span class="o">.</span><span class="n">step</span> <span class="o">+</span> <span class="s1">':</span><span class="se">\n</span><span class="s1">'</span> <span class="o">+</span> + <span class="s1">'please use "by" as well if "to" is used'</span><span class="p">)</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">step</span> <span class="o">=</span> <span class="n">l</span> + + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">levelist</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">levelist</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">levelist</span> + <span class="k">if</span> <span class="s1">'to'</span> <span class="ow">in</span> <span class="n">c</span><span class="o">.</span><span class="n">levelist</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">level</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">levelist</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)[</span><span class="mi">2</span><span class="p">]</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">level</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">levelist</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> + + <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">flexpart_root_scripts</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">flexpart_root_scripts</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">flexpart_root_scripts</span> + + <span class="k">return</span> <span class="n">args</span><span class="p">,</span> <span class="n">c</span></div> + + +<div class="viewcode-block" id="cleanup"><a class="viewcode-back" href="../code.html#Tools.cleanup">[docs]</a><span class="k">def</span> <span class="nf">cleanup</span><span class="p">(</span><span class="n">c</span><span class="p">):</span> + <span class="sd">'''</span> +<span class="sd"> @Description:</span> +<span class="sd"> Remove all files from intermediate directory</span> +<span class="sd"> (inputdir from control file).</span> + +<span class="sd"> @Input:</span> +<span class="sd"> c: instance of class Control</span> +<span class="sd"> Contains all the parameters of control files, which are e.g.:</span> +<span class="sd"> DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME,</span> +<span class="sd"> STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT,</span> +<span class="sd"> LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY,</span> +<span class="sd"> OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT,</span> +<span class="sd"> ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR,</span> +<span class="sd"> MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME</span> +<span class="sd"> DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS</span> + +<span class="sd"> For more information about format and content of the parameter</span> +<span class="sd"> see documentation.</span> + +<span class="sd"> @Return:</span> +<span class="sd"> <nothing></span> +<span class="sd"> '''</span> + + <span class="nb">print</span><span class="p">(</span><span class="s2">"cleanup"</span><span class="p">)</span> + + <span class="n">cleanlist</span> <span class="o">=</span> <span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">inputdir</span> <span class="o">+</span> <span class="s2">"/*"</span><span class="p">)</span> + <span class="k">for</span> <span class="n">cl</span> <span class="ow">in</span> <span class="n">cleanlist</span><span class="p">:</span> + <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">prefix</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">cl</span><span class="p">:</span> + <span class="n">silentremove</span><span class="p">(</span><span class="n">cl</span><span class="p">)</span> + <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">ecapi</span> <span class="ow">is</span> <span class="kc">False</span> <span class="ow">and</span> <span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">ectrans</span> <span class="o">==</span> <span class="s1">'1'</span> <span class="ow">or</span> <span class="n">c</span><span class="o">.</span><span class="n">ecstorage</span> <span class="o">==</span> <span class="s1">'1'</span><span class="p">):</span> + <span class="n">silentremove</span><span class="p">(</span><span class="n">cl</span><span class="p">)</span> + + <span class="nb">print</span><span class="p">(</span><span class="s2">"Done"</span><span class="p">)</span> + + <span class="k">return</span></div> + + +<div class="viewcode-block" id="myerror"><a class="viewcode-back" href="../code.html#Tools.myerror">[docs]</a><span class="k">def</span> <span class="nf">myerror</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">message</span><span class="o">=</span><span class="s1">'ERROR'</span><span class="p">):</span> + <span class="sd">'''</span> +<span class="sd"> @Description:</span> +<span class="sd"> Prints a specified error message which can be passed to the function</span> +<span class="sd"> before exiting the program.</span> + +<span class="sd"> @Input:</span> +<span class="sd"> c: instance of class Control</span> +<span class="sd"> Contains all the parameters of control files, which are e.g.:</span> +<span class="sd"> DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME,</span> +<span class="sd"> STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT,</span> +<span class="sd"> LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY,</span> +<span class="sd"> OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT,</span> +<span class="sd"> ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR,</span> +<span class="sd"> MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME</span> +<span class="sd"> DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS</span> + +<span class="sd"> For more information about format and content of the parameter</span> +<span class="sd"> see documentation.</span> + +<span class="sd"> message: string, optional</span> +<span class="sd"> Error message. Default value is "ERROR".</span> + +<span class="sd"> @Return:</span> +<span class="sd"> <nothing></span> +<span class="sd"> '''</span> + <span class="c1"># uncomment if user wants email notification directly from python</span> + <span class="c1">#try:</span> + <span class="c1">#target = c.mailfail</span> + <span class="c1">#except AttributeError:</span> + <span class="c1">#target = os.getenv('USER')</span> + + <span class="c1">#if(type(target) is not list):</span> + <span class="c1">#target = [target]</span> + + <span class="nb">print</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> + + <span class="c1"># uncomment if user wants email notification directly from python</span> + <span class="c1">#for t in target:</span> + <span class="c1">#p = subprocess.Popen(['mail','-s ECMWFDATA v7.0 ERROR', os.path.expandvars(t)],</span> + <span class="c1"># stdin = subprocess.PIPE, stdout = subprocess.PIPE,</span> + <span class="c1"># stderr = subprocess.PIPE, bufsize = 1)</span> + <span class="c1">#tr = '\n'.join(traceback.format_stack())</span> + <span class="c1">#pout = p.communicate(input = message+'\n\n'+tr)[0]</span> + <span class="c1">#print 'Email sent to '+os.path.expandvars(t) # +' '+pout.decode()</span> + + <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> + + <span class="k">return</span></div> + + +<div class="viewcode-block" id="normalexit"><a class="viewcode-back" href="../code.html#Tools.normalexit">[docs]</a><span class="k">def</span> <span class="nf">normalexit</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">message</span><span class="o">=</span><span class="s1">'Done!'</span><span class="p">):</span> + <span class="sd">'''</span> +<span class="sd"> @Description:</span> +<span class="sd"> Prints a specific exit message which can be passed to the function.</span> + +<span class="sd"> @Input:</span> +<span class="sd"> c: instance of class Control</span> +<span class="sd"> Contains all the parameters of control files, which are e.g.:</span> +<span class="sd"> DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME,</span> +<span class="sd"> STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT,</span> +<span class="sd"> LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY,</span> +<span class="sd"> OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT,</span> +<span class="sd"> ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR,</span> +<span class="sd"> MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME</span> +<span class="sd"> DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS</span> + +<span class="sd"> For more information about format and content of the parameter</span> +<span class="sd"> see documentation.</span> + +<span class="sd"> message: string, optional</span> +<span class="sd"> Message for exiting program. Default value is "Done!".</span> + +<span class="sd"> @Return:</span> +<span class="sd"> <nothing></span> + +<span class="sd"> '''</span> + <span class="c1"># Uncomment if user wants notification directly from python</span> + <span class="c1">#try:</span> + <span class="c1">#target = c.mailops</span> + <span class="c1">#if(type(target) is not list):</span> + <span class="c1">#target = [target]</span> + <span class="c1">#for t in target:</span> + <span class="c1">#p = subprocess.Popen(['mail','-s ECMWFDATA v7.0 normal exit',</span> + <span class="c1"># os.path.expandvars(t)],</span> + <span class="c1"># stdin = subprocess.PIPE,</span> + <span class="c1"># stdout = subprocess.PIPE,</span> + <span class="c1"># stderr = subprocess.PIPE, bufsize = 1)</span> + <span class="c1">#pout = p.communicate(input = message+'\n\n')[0]</span> + <span class="c1">#print pout.decode()</span> + <span class="c1">#except:</span> + <span class="c1">#pass</span> + + <span class="nb">print</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> + + <span class="k">return</span></div> + + +<div class="viewcode-block" id="product"><a class="viewcode-back" href="../code.html#Tools.product">[docs]</a><span class="k">def</span> <span class="nf">product</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwds</span><span class="p">):</span> + <span class="sd">'''</span> +<span class="sd"> @Description:</span> +<span class="sd"> This method is taken from an example at the ECMWF wiki website.</span> +<span class="sd"> https://software.ecmwf.int/wiki/display/GRIB/index.py; 2018-03-16</span> + +<span class="sd"> This method combines the single characters of the passed arguments</span> +<span class="sd"> with each other. So that each character of each argument value</span> +<span class="sd"> will be combined with each character of the other arguments as a tuple.</span> + +<span class="sd"> Example:</span> +<span class="sd"> product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy</span> +<span class="sd"> product(range(2), repeat = 3) --> 000 001 010 011 100 101 110 111</span> + +<span class="sd"> @Input:</span> +<span class="sd"> *args: tuple</span> +<span class="sd"> Positional arguments (arbitrary number).</span> + +<span class="sd"> **kwds: dictionary</span> +<span class="sd"> Contains all the keyword arguments from *args.</span> + +<span class="sd"> @Return:</span> +<span class="sd"> prod: tuple</span> +<span class="sd"> Return will be done with "yield". A tuple of combined arguments.</span> +<span class="sd"> See example in description above.</span> +<span class="sd"> '''</span> + + <span class="n">pools</span> <span class="o">=</span> <span class="nb">map</span><span class="p">(</span><span class="nb">tuple</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span> <span class="o">*</span> <span class="n">kwds</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'repeat'</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> + <span class="n">result</span> <span class="o">=</span> <span class="p">[[]]</span> + <span class="k">for</span> <span class="n">pool</span> <span class="ow">in</span> <span class="n">pools</span><span class="p">:</span> + <span class="n">result</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span> <span class="o">+</span> <span class="p">[</span><span class="n">y</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">result</span> <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="n">pool</span><span class="p">]</span> + <span class="k">for</span> <span class="n">prod</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span> + <span class="k">yield</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">prod</span><span class="p">)</span> + + <span class="k">return</span></div> + + +<div class="viewcode-block" id="silentremove"><a class="viewcode-back" href="../code.html#Tools.silentremove">[docs]</a><span class="k">def</span> <span class="nf">silentremove</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span> + <span class="sd">'''</span> +<span class="sd"> @Description:</span> +<span class="sd"> Removes the file which name is passed to the function if</span> +<span class="sd"> it exists. The function does not fail if the file does not</span> +<span class="sd"> exist.</span> + +<span class="sd"> @Input:</span> +<span class="sd"> filename: string</span> +<span class="sd"> The name of the file to be removed without notification.</span> + +<span class="sd"> @Return:</span> +<span class="sd"> <nothing></span> +<span class="sd"> '''</span> + <span class="k">try</span><span class="p">:</span> + <span class="n">os</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> + <span class="k">except</span> <span class="ne">OSError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> + <span class="c1"># this would be "except OSError, e:" before Python 2.6</span> + <span class="k">if</span> <span class="n">e</span><span class="o">.</span><span class="n">errno</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">errno</span><span class="o">.</span><span class="n">ENOENT</span><span class="p">:</span> + <span class="c1"># errno.ENOENT = no such file or directory</span> + <span class="k">raise</span> <span class="c1"># re-raise exception if a different error occured</span> + + <span class="k">return</span></div> + + +<div class="viewcode-block" id="init128"><a class="viewcode-back" href="../code.html#Tools.init128">[docs]</a><span class="k">def</span> <span class="nf">init128</span><span class="p">(</span><span class="n">fn</span><span class="p">):</span> + <span class="sd">'''</span> +<span class="sd"> @Description:</span> +<span class="sd"> Opens and reads the grib file with table 128 information.</span> + +<span class="sd"> @Input:</span> +<span class="sd"> fn: string</span> +<span class="sd"> Path to file of ECMWF grib table number 128.</span> + +<span class="sd"> @Return:</span> +<span class="sd"> table128: dictionary</span> +<span class="sd"> Contains the ECMWF grib table 128 information.</span> +<span class="sd"> The key is the parameter number and the value is the</span> +<span class="sd"> short name of the parameter.</span> +<span class="sd"> '''</span> + <span class="n">table128</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span> + <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">fn</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span> + <span class="n">fdata</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'</span><span class="se">\n</span><span class="s1">'</span><span class="p">)</span> + <span class="k">for</span> <span class="n">data</span> <span class="ow">in</span> <span class="n">fdata</span><span class="p">:</span> + <span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="s1">'!'</span><span class="p">:</span> + <span class="n">table128</span><span class="p">[</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">3</span><span class="p">]]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="mi">59</span><span class="p">:</span><span class="mi">64</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> + + <span class="k">return</span> <span class="n">table128</span></div> + + +<div class="viewcode-block" id="toparamId"><a class="viewcode-back" href="../code.html#Tools.toparamId">[docs]</a><span class="k">def</span> <span class="nf">toparamId</span><span class="p">(</span><span class="n">pars</span><span class="p">,</span> <span class="n">table</span><span class="p">):</span> + <span class="sd">'''</span> +<span class="sd"> @Description:</span> +<span class="sd"> Transform parameter names to parameter ids</span> +<span class="sd"> with ECMWF grib table 128.</span> + +<span class="sd"> @Input:</span> +<span class="sd"> pars: string</span> +<span class="sd"> Addpar argument from control file in the format of</span> +<span class="sd"> parameter names instead of ids. The parameter short</span> +<span class="sd"> names are sepearted with "/" and they are passed as</span> +<span class="sd"> one single string.</span> + +<span class="sd"> table: dictionary</span> +<span class="sd"> Contains the ECMWF grib table 128 information.</span> +<span class="sd"> The key is the parameter number and the value is the</span> +<span class="sd"> short name of the parameter.</span> + +<span class="sd"> @Return:</span> +<span class="sd"> ipar: list of integer</span> +<span class="sd"> List of addpar parameters from control file transformed to</span> +<span class="sd"> parameter ids in the format of integer.</span> +<span class="sd"> '''</span> + <span class="n">cpar</span> <span class="o">=</span> <span class="n">pars</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span> + <span class="n">ipar</span> <span class="o">=</span> <span class="p">[]</span> + <span class="k">for</span> <span class="n">par</span> <span class="ow">in</span> <span class="n">cpar</span><span class="p">:</span> + <span class="n">found</span> <span class="o">=</span> <span class="kc">False</span> + <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">table</span><span class="o">.</span><span class="n">iteritems</span><span class="p">():</span> + <span class="k">if</span> <span class="n">par</span> <span class="o">==</span> <span class="n">k</span> <span class="ow">or</span> <span class="n">par</span> <span class="o">==</span> <span class="n">v</span><span class="p">:</span> + <span class="n">ipar</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">k</span><span class="p">))</span> + <span class="n">found</span> <span class="o">=</span> <span class="kc">True</span> + <span class="k">break</span> + <span class="k">if</span> <span class="n">found</span> <span class="ow">is</span> <span class="kc">False</span><span class="p">:</span> + <span class="nb">print</span><span class="p">(</span><span class="s1">'Warning: par '</span> <span class="o">+</span> <span class="n">par</span> <span class="o">+</span> <span class="s1">' not found in table 128'</span><span class="p">)</span> + + <span class="k">return</span> <span class="n">ipar</span></div> + +<div class="viewcode-block" id="getListAsString"><a class="viewcode-back" href="../code.html#Tools.getListAsString">[docs]</a><span class="k">def</span> <span class="nf">getListAsString</span><span class="p">(</span><span class="n">listobj</span><span class="p">):</span> + <span class="sd">'''</span> +<span class="sd"> @Description:</span> +<span class="sd"> '''</span> + <span class="k">return</span> <span class="s2">", "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span> <span class="nb">str</span><span class="p">(</span><span class="n">l</span><span class="p">)</span> <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">listobj</span><span class="p">)</span></div> +</pre></div> + + </div> + </div> + </div> + <div class="sphinxsidebar" role="navigation" aria-label="main navigation"> + <div class="sphinxsidebarwrapper"> +<div id="searchbox" style="display: none" role="search"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <div><input type="text" name="q" /></div> + <div><input type="submit" value="Go" /></div> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + >index</a></li> + <li class="right" > + <a href="../py-modindex.html" title="Python Module Index" + >modules</a> |</li> + <li class="nav-item nav-item-0"><a href="../index.html">flex_extract_test 7.1 documentation</a> »</li> + <li class="nav-item nav-item-1"><a href="index.html" >Module code</a> »</li> + </ul> + </div> + <div class="footer" role="contentinfo"> + © Copyright 2018, AP. + Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6. + </div> + </body> +</html> \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/html/_modules/index.html b/for_developers/SphinxDoc/_build/html/_modules/index.html new file mode 100644 index 0000000..4b82cec --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_modules/index.html @@ -0,0 +1,87 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Overview: module code — flex_extract_test 7.1 documentation</title> + <link rel="stylesheet" href="../_static/classic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '7.1', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + </head> + <body> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="../py-modindex.html" title="Python Module Index" + >modules</a> |</li> + <li class="nav-item nav-item-0"><a href="../index.html">flex_extract_test 7.1 documentation</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body" role="main"> + + <h1>All modules for which code is available</h1> +<ul><li><a href="Control.html">Control</a></li> +<li><a href="Tools.html">Tools</a></li> +</ul> + + </div> + </div> + </div> + <div class="sphinxsidebar" role="navigation" aria-label="main navigation"> + <div class="sphinxsidebarwrapper"> +<div id="searchbox" style="display: none" role="search"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <div><input type="text" name="q" /></div> + <div><input type="submit" value="Go" /></div> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + >index</a></li> + <li class="right" > + <a href="../py-modindex.html" title="Python Module Index" + >modules</a> |</li> + <li class="nav-item nav-item-0"><a href="../index.html">flex_extract_test 7.1 documentation</a> »</li> + </ul> + </div> + <div class="footer" role="contentinfo"> + © Copyright 2018, AP. + Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6. + </div> + </body> +</html> \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/html/_sources/code.rst.txt b/for_developers/SphinxDoc/_build/html/_sources/code.rst.txt new file mode 100644 index 0000000..342bc36 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_sources/code.rst.txt @@ -0,0 +1,8 @@ +Auto Generated Documentation +============================ + +.. automodule:: Tools + :members: + +.. autoclass:: Control + :members: diff --git a/for_developers/SphinxDoc/_build/html/_sources/index.rst.txt b/for_developers/SphinxDoc/_build/html/_sources/index.rst.txt new file mode 100644 index 0000000..d720b19 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_sources/index.rst.txt @@ -0,0 +1,20 @@ +.. flex_extract_test documentation master file, created by + sphinx-quickstart on Sun May 6 19:28:54 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to flex_extract_test's documentation! +============================================= + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + code + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/for_developers/SphinxDoc/_build/html/_static/ajax-loader.gif b/for_developers/SphinxDoc/_build/html/_static/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..61faf8cab23993bd3e1560bff0668bd628642330 GIT binary patch literal 673 zcmZ?wbhEHb6krfw_{6~Q|Nno%(3)e{?)x>&6%4J(nYONL^}d<gjw$|=axO|uEJ;mK zD9<d(P)N*5tjNhvOwr5COUq|a{K>+=#lXOz_@CR)H6+;CF~HSG&w!bcfq_AXfq{Vm zWH<w}F~_bu{|rufW(y~CSaC?sVfUMn#_77z@X#)inFqJ&B^)_actJN>!t(Aic1sB! zcCYN`9t=>U8IjE~0h#01qo^R=!n1qBvo4oHr@)W|LrH}MAJ=H96*V$jOYgr;lwfaA zxGwRi%~^7js*08n)F38ggUmQ~87XU@ay&8N%#<*Fw$@}BzAut~A3dECXRI!e`M`B% z^In-_E3}y+--`cXY(C6yv@%6%{(csyQOw9j8FTDPQq?|X)Hd<WoUr)T?q!^<iaaca zF71gjf~(w`He8fvP6~?sY%6bIp(E9QVo8yu56o{Y$mSSv>?%^%_IjQo@<HOWPa}_7 z+2Mqkq>w4CEj#5hBAqnPpK=gjmV0R<e^?D{PS7NnF|5eO7<24WI5fdh{Bg<iJ-6l= zNFJAYps44xZSJY?HH!>+*tkWC6L)Vg{XUhk(O?5-=kEErnqDw-*pSUJ0tNL4PQjaV zLStt!zPnXeFg2m$ZsMG~CevCS-HsZFOh}l$jggn-kb}T%!-hlG&P{|F!;WE$!70zx zsZLksXkM4&;5e+%cf62~#n52osSWD_Bn~A?u!r4R%A`=5B+)c4T5tjbgEc7OfH45| CAl1tN literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/html/_static/basic.css b/for_developers/SphinxDoc/_build/html/_static/basic.css new file mode 100644 index 0000000..6f40830 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_static/basic.css @@ -0,0 +1,643 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 170px; +} + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/html/_static/classic.css b/for_developers/SphinxDoc/_build/html/_static/classic.css new file mode 100644 index 0000000..6cfbfb9 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_static/classic.css @@ -0,0 +1,261 @@ +/* + * classic.css_t + * ~~~~~~~~~~~~~ + * + * Sphinx stylesheet -- classic theme. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: sans-serif; + font-size: 100%; + background-color: #11303d; + color: #000; + margin: 0; + padding: 0; +} + +div.document { + background-color: #1c4e63; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 230px; +} + +div.body { + background-color: #ffffff; + color: #000000; + padding: 0 20px 30px 20px; +} + +div.footer { + color: #ffffff; + width: 100%; + padding: 9px 0 9px 0; + text-align: center; + font-size: 75%; +} + +div.footer a { + color: #ffffff; + text-decoration: underline; +} + +div.related { + background-color: #133f52; + line-height: 30px; + color: #ffffff; +} + +div.related a { + color: #ffffff; +} + +div.sphinxsidebar { +} + +div.sphinxsidebar h3 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.4em; + font-weight: normal; + margin: 0; + padding: 0; +} + +div.sphinxsidebar h3 a { + color: #ffffff; +} + +div.sphinxsidebar h4 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.3em; + font-weight: normal; + margin: 5px 0 0 0; + padding: 0; +} + +div.sphinxsidebar p { + color: #ffffff; +} + +div.sphinxsidebar p.topless { + margin: 5px 10px 10px 10px; +} + +div.sphinxsidebar ul { + margin: 10px; + padding: 0; + color: #ffffff; +} + +div.sphinxsidebar a { + color: #98dbcc; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + + + +/* -- hyperlink styles ------------------------------------------------------ */ + +a { + color: #355f7c; + text-decoration: none; +} + +a:visited { + color: #355f7c; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + + + +/* -- body styles ----------------------------------------------------------- */ + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: 'Trebuchet MS', sans-serif; + background-color: #f2f2f2; + font-weight: normal; + color: #20435c; + border-bottom: 1px solid #ccc; + margin: 20px -20px 10px -20px; + padding: 3px 0 3px 10px; +} + +div.body h1 { margin-top: 0; font-size: 200%; } +div.body h2 { font-size: 160%; } +div.body h3 { font-size: 140%; } +div.body h4 { font-size: 120%; } +div.body h5 { font-size: 110%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: #c60f0f; + color: white; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + text-align: justify; + line-height: 130%; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.admonition p { + margin-bottom: 5px; +} + +div.admonition pre { + margin-bottom: 5px; +} + +div.admonition ul, div.admonition ol { + margin-bottom: 5px; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: #eee; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre { + padding: 5px; + background-color: #eeffcc; + color: #333333; + line-height: 120%; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +code { + background-color: #ecf0f3; + padding: 0 1px 0 1px; + font-size: 0.95em; +} + +th { + background-color: #ede; +} + +.warning code { + background: #efc2c2; +} + +.note code { + background: #d6d6d6; +} + +.viewcode-back { + font-family: sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} + +div.code-block-caption { + color: #efefef; + background-color: #1c4e63; +} \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/html/_static/comment-bright.png b/for_developers/SphinxDoc/_build/html/_static/comment-bright.png new file mode 100644 index 0000000000000000000000000000000000000000..15e27edb12ac25701ac0ac21b97b52bb4e45415e GIT binary patch literal 756 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!toc6+)whEy=NPG&yv#73a) z{>&wJ|K{G_mV0|!A&3Am7t7!BeKyPXcjsI|zRxZTcUqiy{H5e(@Amqb>d(^euipG} zTiVp@@Bgf&z4Pq?^X>|Z*BSp3n$xwr_>9Y}>f85z<?mh_tj%|G_wE}Fwv)CW&-=Og za^BB{XZgYp+248>QJUNLlU3le<J6-bpFOv#7TAOp9e&JO{qD><bG;3!?C-X-{(86Z zf9Y-Y{bhHw_m|vLw%>YN_5RlTssH=+YgRp47GuG3@MF~T=+z<>>48U{<a2Vk6bdr0 zmY5_I!Pq0p$$O&3?cC>1w)6Mqr-we3&eA^eWc|I83##Hj&DkbeYbnk0%xp_)>WgmM zJ*AVAK{z#fV)XhCd3TGBny>vj`>I)d`8ms1*VZx$NH&-TPhz~(V#2mTr$eXFnQgMD zpi*+d*VyuyVpHj5tG~6DBx+2%k(_b#!(=I|g%7LQqxBa)_+4;x?d0{6O+RE09kntx zIeEt8iz{c_HwOE>scbf^8(gFQX(VlM>uKE)HK!s;#dYGnt;ch`C8Y&ka@+XNx$`7* zYTeYA4_Hqau)78}Y$#OXJo4_|+^Jh9Ue}M^k#}_08{Sjl3Smp82;Kkt<j#&c{3_?S ze>m5#|K-G5ZsYDx9n;pHpJTH5O7HE8`19L0ndNeF>Bj65R}(UDSS0$Wr}+GFN9_s1 zGZ|Ug*G7ouNX7rSbzb1`(KgO$A^X?fe<b?b{?-<=31@F_S}^ygv%=J;EM?Oh=KK&p z=F~rLU-8EsouB0zA3wD7D1O?XJn>oQHU9d@{Krf3XT7}<U){NNt9X>Ai3LaT*IS$4 z-~V=d`uz{TTTWTX@{30H9^MmK{P{taaqp3XCQr7>6vypQK0fL9hmzCXg)_3F9&EWY zr~K{R{afyDwd*^ixMTIhpB8=h3&QgLRR6lV{g3U_Je5_y3u2zeS=+KROqgW7wYOX% RfPsO5!PC{xWt~$(695E=cnkml literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/html/_static/comment-close.png b/for_developers/SphinxDoc/_build/html/_static/comment-close.png new file mode 100644 index 0000000000000000000000000000000000000000..4d91bcf57de866a901a89a2a68c0f36af1114841 GIT binary patch literal 829 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!toSv*}FLn;_^&oR&WY9Z40 z@w>`fiR{mtb8l~hqq~mpeb1#8T>t-Xo>hbYvvuME>cXkgA5;Q&7M|ytF7tm&;=_yn z(V`N+mN-3Y<Tq{)z5m_vpZ}(7=>pnEn^<(k_E{LF{BAF|HQ)c7Z}t7c$xGkw`1a?z z;m%(1J^Ow;zxJM+I7P0GcjKx4J$(|AzirN4Nj*FJMJK!L-SpGycPkH9-z|FTp10u% z^Y!>|^Iq%KoHiBTdv)!ZmdJLS-0q4N3D)VV68Cog2<=zc|D3P!#1XD2t_{-{N(Rij z8LIG9i|?EAt+IE)zjq(5lT%MDkuptw{rq9wehWDzCgbR)C8`Rn2aUoRnI;;rGdPN@ zohe+Ct6uT1^lN3<#EIwYczC98##uDDGalmM6JUsJiQu}>^zb6fLoSX>XMC23?DL-W z<M(?V)fcz>^;$inCvQ>JVZ8BANQX0QOLv3+`h!sqlRrFHu$L}i{b~5%`=i1K6K>{e zMNC}B)$wJ6=sW#{n+@}KdU0=1{qTEb?FrMx_A?r7d8;31?P^M3n8j)|_ij_kcD}1y z@9hiM-|J=V61F1Oc!|O$UCG_uD#y1!x-I?OA!_k~H;ffG)j996*R*Y6H!q%N`#GUH z*4t)R;nRn2+b{MnozKGQ8RYe?`=+Nr!D_GEJ)U!zPHp;lb?<5oyPe#da%P{Ox_sMG zdAV5ONmrShCT_X>_R>k=)^+}KO{O$8=iE>fay;nZ!118`vD~IFdHwVI-?CNioe;;r z<kO*wM6Jeo){=&kO7{ity7(u2*WG3QHvhC<cbd;gw@aE=H^1`Uyxo5ka{aC`Y(5#Y zSW=^}<h9`I*;ecV+MoB7gsRzDM%6xh?f-aPw(YyFXX|dulwawv?GqMxm)h|7cScq| zSEK)}ci$fbr<~cGt9)K#oza(D>v}u8zICX*R%8xTJO0Jy-@mn)91r8`UVl)C{KvC! zx14SNu01QfAEn-3;eVL1Wv0w!h0B_kV=n8f@&9`}J#G2E-+OO<O!*-H^!R~EKSJNn lT=jd~8HZy($|u${T&XN<Q2uMVmw|zS!PC{xWt~$(695H8lQjSU literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/html/_static/comment.png b/for_developers/SphinxDoc/_build/html/_static/comment.png new file mode 100644 index 0000000000000000000000000000000000000000..dfbc0cbd512bdeefcb1984c99d8e577efb77f006 GIT binary patch literal 641 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!toJUm?-Ln;_sCouQO#)}+# z-hV4B<aXGd4Sj*fw~DTI3o&1nyF2#%8=L;KzRkDZ?zMexr}BDo&CWk{>@jv~dA^&z zet78p-$px}O@#B;8uO-Yk3`q6tvb1yd;YYO!sqRK${)SzR$R@xZJtH^MSp>{TsJ@5 zTW&I4O{AS`k?-kXu~+KzH?Eb|zcl;f`#H8n*Y+gLKNNPtKyl>``x12($-BxM)SI3J z$T1`=nVQL#SRU~3mXzq6T?fB6ud#PIytwdY;~72Cgrj>E7Uo2$TCzCuFkPs2y|jx- zLD4#OmTW@WtdQ7A0kKie3@#GPoqTK0L@Y5%)x17``R$_hm23T@itjgF=wRTgo@HpW zY)YF}gMd@T#I0W*vaaWSkZ|g;(5BzAy&7wrOqypI)y%q<?XY30{DZj%Y}W@YbFAM# z^X7?Jsn!d)JkGA&6w2K6_Cdmar>~25wjaIZpz)G<isu92gXd=n2i@ge`Os~L(h7#e zw;Foq6l#LB${(M*CmiLZpA_|-Gp+qRi|;b|K<$ndk|~N^XKyJQ2%D`IpZdyFPyT!N z5lh!XW^D%s;{`W6SFMx{3qIW4@hXMUV)3IHa$;w!=U-rAQS&bF$S`1NNV8^Wkl%Pp zB;#@9PMz2qk@p9ElJim(?~3nFd)?_Rn(Xz+Ewl2{pB@2$Z-0U(%=K@|czu1IYI!m5 z(HC#a694b=s$OxB;XcQ$#n$@4#_#u@<FPMXx+wXf^ZLs%&4uedWSG|eSYPq>;>Y6D z+?`Szo3f4aZ2Z5n@LE>wSz_6Kaq+_(iF!u<D<xVxrH$V*FfcH9y85}Sb4q9e0F6u^ A0RR91 literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/html/_static/doctools.js b/for_developers/SphinxDoc/_build/html/_static/doctools.js new file mode 100644 index 0000000..0c15c00 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_static/doctools.js @@ -0,0 +1,311 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var bbox = span.getBBox(); + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + var parentOfText = node.parentNode.parentNode; + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('<a class="headerlink">\u00B6</a>'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('<a class="headerlink">\u00B6</a>'). + 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); + $('<p class="highlight-link"><a href="javascript:Documentation.' + + 'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/html/_static/down-pressed.png b/for_developers/SphinxDoc/_build/html/_static/down-pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..5756c8cad8854722893dc70b9eb4bb0400343a39 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7mU_B4hEy;n-;j|%f5t(M z;WewEmqU(sTUzvlIEi#sfq2G85(>`_F79Ms^^D7df7cUlg@5cv_BZ|z7m#Oo<f72m zzNy~v>A%J+Nyc|sJN`S1{&7E^QKYwHP6g|d28Ml2`Uw#YKe+kA|1_W4D8O~sh-baR zjnpG<7qxZtDqOu}xS2l6uQ>aEL5^dP@F^~p+u;*thuAk6FtcXf6=~5lY+#kiZI)tS ZILEaAd}8SP4Gatn44$rjF6*2UngDJmP>BEl literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/html/_static/down.png b/for_developers/SphinxDoc/_build/html/_static/down.png new file mode 100644 index 0000000000000000000000000000000000000000..1b3bdad2ceffae91cee61b32f3295f9bbe646e48 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4i*LmhONKMUokK+O!Rbd45?sT+p~3HbAX7$ z`|0m~bG>o!JT7*BdV<;vr7E)uZwJxrr1Og^rWVJxvcEj&%h_RdT(FT}vP*xS_Tuz? z0V&Uo+&8Blo={&m_x=vA$?@Nld8C4c;*UO^&J`@Inp%+(`fFkASB+4QKMy|HO;i(^ z&fmJ_AiK56t)Kjv?IMp=rsmBso^Hp%`CDABa*A{^<I9gN>r+~8i7_xRFnGH9xvX<a GXaWFP8cnDG literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/html/_static/file.png b/for_developers/SphinxDoc/_build/html/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7o_e}ChEy=Fo!lJ6#wgPI zU9-A1=eok}ZEQDX(r(*2tb58m$7=u1ea82H)jeO=^6%fjou57xMW{G_5a*B3{pP}1 zS6~0}?_b_epFayX9PiZV3J_7<*U-z(&Te62!(wS=#r62dj~f93Q(yV3O;UNueM4ey zPF+*P_cxDwe?L<@A-VUOYxn_?IFqgAjDfX>&K+iC+ZOj{hWM55XBY3QXXIt>UXl5V zY32J_2KpZQFCE-8U%FHkYESx{HDO9L>%8Dl(|ry6XI@BV%vz@ZVSj$)G){LlpS0qd r#>Mpuckiw~`|AFW`^Ks}LhH4IH@r-6bi2gBz`)??>gTe~DWM4fp;vuF literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/html/_static/jquery-3.1.0.js b/for_developers/SphinxDoc/_build/html/_static/jquery-3.1.0.js new file mode 100644 index 0000000..f2fc274 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_static/jquery-3.1.0.js @@ -0,0 +1,10074 @@ +/*eslint-disable no-unused-vars*/ +/*! + * jQuery JavaScript Library v3.1.0 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2016-07-07T21:44Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc 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.1.0", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num != null ? + + // Return just the one element from the set + ( num < 0 ? this[ num + this.length ] : this[ num ] ) : + + // Return all the elements in a clean array + slice.call( this ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = jQuery.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isArray: Array.isArray, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.0 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-01-04 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + // Known :disabled false positives: + // IE: *[disabled]:not(button, input, select, textarea, optgroup, option, menuitem, fieldset) + // not IE: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Check form elements and option elements for explicit disabling + return "label" in elem && elem.disabled === disabled || + "form" in elem && elem.disabled === disabled || + + // Check non-disabled form elements for fieldset[disabled] ancestors + "form" in elem && elem.disabled === false && ( + // Support: IE6-11+ + // Ancestry is covered for us + elem.isDisabled === disabled || + + // Otherwise, assume any non-<option> under fieldset[disabled] is disabled + /* jshint -W018 */ + elem.isDisabled !== !disabled && + ("label" in elem || !disabledAncestor( elem )) !== disabled + ); + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID find and filter + if ( support.getById ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var m = context.getElementById( id ); + return m ? [ m ] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + // Support: IE6/7 + // getElementById is not reliable as a find shortcut + delete Expr.find["ID"]; + + 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; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" + + "<select id='" + expando + "-\r\\' msallowcapture=''>" + + "<option selected=''></option></select>"; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "<a href='' disabled='disabled'></a>" + + "<select disabled='disabled'><option/></select>"; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // 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; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + support.getById && 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 = "<a href='#'></a>"; + 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 = "<input/>"; + 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; + +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + + } + + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + + } + + if ( typeof qualifier === "string" ) { + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + qualifier = jQuery.filter( qualifier, elements ); + } + + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 && elem.nodeType === 1 ? + jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : + 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 <tag> to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + return elem.contentDocument || 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 rnotwhite = ( /\S+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnotwhite ) || [], 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 = options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + resolve.call( undefined, value ); + } + + // 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.call( undefined, value ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( jQuery.isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ jQuery.camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( jQuery.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( jQuery.camelCase ); + } else { + key = jQuery.camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnotwhite ) || [] ); + } + + 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 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 = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? JSON.parse( data ) : + data; + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ), + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "<select multiple='multiple'>", "</select>" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting <tbody> or other required elements. + thead: [ 1, "<table>", "</table>" ], + col: [ 2, "<table><colgroup>", "</colgroup></table>" ], + tr: [ 2, "<table><tbody>", "</tbody></table>" ], + td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== "undefined" ? + context.querySelectorAll( tag || "*" ) : + []; + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], ret ) : + ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = "<textarea>x</textarea>"; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + 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( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, matches, sel, handleObj, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Support: IE <=9 + // Find delegate handlers + // Black-hole SVG <use> instance trees (#13180) + // + // Support: Firefox <=42 + // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343) + if ( delegateCount && cur.nodeType && + ( event.type !== "click" || isNaN( event.button ) || 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 && ( cur.disabled !== true || event.type !== "click" ) ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push( { elem: cur, handlers: matches } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + return ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /<script|<style|<link/i, + + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptTypeMasked = /^true\/(.*)/, + rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g; + +function manipulationTarget( elem, content ) { + if ( jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return elem.getElementsByTagName( "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 ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1></$2>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + style = elem.style; + + computed = computed || getStyles( elem ); + + // Support: IE <=9 only + // getPropertyValue is only needed for .css('filter') (#12537) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i = extra === ( isBorderBox ? "border" : "content" ) ? + + // If we already have the right measurement, avoid augmentation + 4 : + + // Otherwise initialize for horizontal or vertical properties + name === "width" ? 1 : 0, + + val = 0; + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with offset property, which is equivalent to the border-box value + var val, + valueIsBorderBox = true, + styles = getStyles( elem ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + if ( elem.getClientRects().length ) { + val = elem.getBoundingClientRect()[ name ]; + } + + // Some non-html elements return undefined for offsetWidth, so check for null/undefined + // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 + // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 + if ( val <= 0 || val == null ) { + + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name, styles ); + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + } + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + } + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + style = elem.style; + + name = jQuery.cssProps[ origName ] || + ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName ); + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + style[ name ] = value; + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ); + + // Make sure that we're working with the right name + name = jQuery.cssProps[ origName ] || + ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName ); + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( jQuery.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, timerId, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function raf() { + if ( timerId ) { + window.requestAnimationFrame( raf ); + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( jQuery.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 ( percent < 1 && length ) { + return remaining; + } else { + deferred.resolveWith( elem, [ animation ] ); + return false; + } + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + // attach callbacks from options + return animation.progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnotwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off or if document is hidden + if ( jQuery.fx.off || document.hidden ) { + opt.duration = 0; + + } else { + opt.duration = typeof opt.duration === "number" ? + opt.duration : opt.duration in jQuery.fx.speeds ? + jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Checks the timer has not already been removed + 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 ); + if ( timer() ) { + jQuery.fx.start(); + } else { + jQuery.timers.pop(); + } +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( !timerId ) { + timerId = window.requestAnimationFrame ? + window.requestAnimationFrame( raf ) : + window.setInterval( jQuery.fx.tick, jQuery.fx.interval ); + } +}; + +jQuery.fx.stop = function() { + if ( window.cancelAnimationFrame ) { + window.cancelAnimationFrame( timerId ); + } else { + window.clearInterval( timerId ); + } + + timerId = 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" && + jQuery.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, + attrNames = value && value.match( rnotwhite ); + + 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" ); + + return tabindex ? + parseInt( tabindex, 10 ) : + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && elem.href ? + 0 : + -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 +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + 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; +} ); + + + + +var rclass = /[\t\r\n\f]/g; + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnotwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && + ( " " + curValue + " " ).replace( rclass, " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = jQuery.trim( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnotwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && + ( " " + curValue + " " ).replace( rclass, " " ); + + 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 = jQuery.trim( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnotwhite ) || []; + + 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 && + ( " " + getClass( elem ) + " " ).replace( rclass, " " ) + .indexOf( className ) > -1 + ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g, + rspaces = /[\x20\t\r\n\f]+/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, isFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + + // Handle most common string cases + ret.replace( rreturn, "" ) : + + // Handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( jQuery.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 + jQuery.trim( jQuery.text( elem ) ).replace( rspaces, " " ); + } + }, + select: { + get: function( elem ) { + var value, option, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? + max : + 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 || + !jQuery.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 ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( jQuery.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( jQuery.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(); + + return val == null ? + null : + jQuery.isArray( val ) ? + jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ) : + { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rts = /([?&])_=[^&]*/, + 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( rnotwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add anti-cache in uncached url if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rts, "" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( "<script>" ).prop( { + charset: s.scriptCharset, + src: s.url + } ).on( + "load error", + callback = function( evt ) { + script.remove(); + callback = null; + if ( evt ) { + complete( evt.type === "error" ? 404 : 200, evt.type ); + } + } + ); + + // Use native DOM manipulation to avoid our domManip AJAX trickery + document.head.appendChild( script[ 0 ] ); + }, + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +var oldCallbacks = [], + rjsonp = /(=)\?(?=&|$)|\?\?/; + +// Default jsonp settings +jQuery.ajaxSetup( { + jsonp: "callback", + jsonpCallback: function() { + var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); + this[ callback ] = true; + return callback; + } +} ); + +// Detect, normalize options and install callbacks for jsonp requests +jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { + + var callbackName, overwritten, responseContainer, + jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ? + "url" : + typeof s.data === "string" && + ( s.contentType || "" ) + .indexOf( "application/x-www-form-urlencoded" ) === 0 && + rjsonp.test( s.data ) && "data" + ); + + // Handle iff the expected data type is "jsonp" or we have a parameter to set + if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { + + // Get callback name, remembering preexisting value associated with it + callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? + s.jsonpCallback() : + s.jsonpCallback; + + // Insert callback into url or form data + if ( jsonProp ) { + s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName ); + } else if ( s.jsonp !== false ) { + s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; + } + + // Use data converter to retrieve json after script execution + s.converters[ "script json" ] = function() { + if ( !responseContainer ) { + jQuery.error( callbackName + " was not called" ); + } + return responseContainer[ 0 ]; + }; + + // Force json dataType + s.dataTypes[ 0 ] = "json"; + + // Install callback + overwritten = window[ callbackName ]; + window[ callbackName ] = function() { + responseContainer = arguments; + }; + + // Clean-up function (fires after converters) + jqXHR.always( function() { + + // If previous value didn't exist - remove it + if ( overwritten === undefined ) { + jQuery( window ).removeProp( callbackName ); + + // Otherwise restore preexisting value + } else { + window[ callbackName ] = overwritten; + } + + // Save back as free + if ( s[ callbackName ] ) { + + // Make sure that re-using the options doesn't screw things around + s.jsonpCallback = originalSettings.jsonpCallback; + + // Save the callback name for future use + oldCallbacks.push( callbackName ); + } + + // Call if it was a function and we have a response + if ( responseContainer && jQuery.isFunction( overwritten ) ) { + overwritten( responseContainer[ 0 ] ); + } + + responseContainer = overwritten = undefined; + } ); + + // Delegate to script + return "script"; + } +} ); + + + + +// Support: Safari 8 only +// In Safari 8 documents created via document.implementation.createHTMLDocument +// collapse sibling forms: the second one becomes a child of the first one. +// Because of that, this security measure has to be disabled in Safari 8. +// https://bugs.webkit.org/show_bug.cgi?id=137337 +support.createHTMLDocument = ( function() { + var body = document.implementation.createHTMLDocument( "" ).body; + body.innerHTML = "<form></form><form></form>"; + return body.childNodes.length === 2; +} )(); + + +// Argument "data" should be string of html +// context (optional): If specified, the fragment will be created in this context, +// defaults to document +// keepScripts (optional): If true, will include scripts passed in the html string +jQuery.parseHTML = function( data, context, keepScripts ) { + if ( typeof data !== "string" ) { + return []; + } + if ( typeof context === "boolean" ) { + keepScripts = context; + context = false; + } + + var base, parsed, scripts; + + if ( !context ) { + + // Stop scripts or inline event handlers from being executed immediately + // by using document.implementation + if ( support.createHTMLDocument ) { + context = document.implementation.createHTMLDocument( "" ); + + // Set the base href for the created document + // so any parsed elements with URLs + // are based on the document's URL (gh-2965) + base = context.createElement( "base" ); + base.href = document.location.href; + context.head.appendChild( base ); + } else { + context = document; + } + } + + parsed = rsingleTag.exec( data ); + scripts = !keepScripts && []; + + // Single tag + if ( parsed ) { + return [ context.createElement( parsed[ 1 ] ) ]; + } + + parsed = buildFragment( [ data ], context, scripts ); + + if ( scripts && scripts.length ) { + jQuery( scripts ).remove(); + } + + return jQuery.merge( [], parsed.childNodes ); +}; + + +/** + * Load a url into a page + */ +jQuery.fn.load = function( url, params, callback ) { + var selector, type, response, + self = this, + off = url.indexOf( " " ); + + if ( off > -1 ) { + selector = jQuery.trim( url.slice( off ) ); + url = url.slice( 0, off ); + } + + // If it's a function + if ( jQuery.isFunction( params ) ) { + + // We assume that it's the callback + callback = params; + params = undefined; + + // Otherwise, build a param string + } else if ( params && typeof params === "object" ) { + type = "POST"; + } + + // If we have elements to modify, make the request + if ( self.length > 0 ) { + jQuery.ajax( { + url: url, + + // If "type" variable is undefined, then "GET" method will be used. + // Make value of this field explicit since + // user can override it through ajaxSetup method + type: type || "GET", + dataType: "html", + data: params + } ).done( function( responseText ) { + + // Save response for use in complete callback + response = arguments; + + self.html( selector ? + + // If a selector was specified, locate the right elements in a dummy div + // Exclude scripts to avoid IE 'Permission Denied' errors + jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) : + + // Otherwise use the full result + responseText ); + + // If the request succeeds, this function gets "data", "status", "jqXHR" + // but they are ignored because response was set above. + // If it fails, this function gets "jqXHR", "status", "error" + } ).always( callback && function( jqXHR, status ) { + self.each( function() { + callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] ); + } ); + } ); + } + + return this; +}; + + + + +// Attach a bunch of functions for handling common AJAX events +jQuery.each( [ + "ajaxStart", + "ajaxStop", + "ajaxComplete", + "ajaxError", + "ajaxSuccess", + "ajaxSend" +], function( i, type ) { + jQuery.fn[ type ] = function( fn ) { + return this.on( type, fn ); + }; +} ); + + + + +jQuery.expr.pseudos.animated = function( elem ) { + return jQuery.grep( jQuery.timers, function( fn ) { + return elem === fn.elem; + } ).length; +}; + + + + +/** + * Gets a window from an element + */ +function getWindow( elem ) { + return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView; +} + +jQuery.offset = { + setOffset: function( elem, options, i ) { + var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, + position = jQuery.css( elem, "position" ), + curElem = jQuery( elem ), + props = {}; + + // Set position first, in-case top/left are set even on static elem + if ( position === "static" ) { + elem.style.position = "relative"; + } + + curOffset = curElem.offset(); + curCSSTop = jQuery.css( elem, "top" ); + curCSSLeft = jQuery.css( elem, "left" ); + calculatePosition = ( position === "absolute" || position === "fixed" ) && + ( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1; + + // Need to be able to calculate position if either + // top or left is auto and position is either absolute or fixed + if ( calculatePosition ) { + curPosition = curElem.position(); + curTop = curPosition.top; + curLeft = curPosition.left; + + } else { + curTop = parseFloat( curCSSTop ) || 0; + curLeft = parseFloat( curCSSLeft ) || 0; + } + + if ( jQuery.isFunction( options ) ) { + + // Use jQuery.extend here to allow modification of coordinates argument (gh-1848) + options = options.call( elem, i, jQuery.extend( {}, curOffset ) ); + } + + if ( options.top != null ) { + props.top = ( options.top - curOffset.top ) + curTop; + } + if ( options.left != null ) { + props.left = ( options.left - curOffset.left ) + curLeft; + } + + if ( "using" in options ) { + options.using.call( elem, props ); + + } else { + curElem.css( props ); + } + } +}; + +jQuery.fn.extend( { + offset: function( options ) { + + // Preserve chaining for setter + if ( arguments.length ) { + return options === undefined ? + this : + this.each( function( i ) { + jQuery.offset.setOffset( this, options, i ); + } ); + } + + var docElem, win, rect, doc, + elem = this[ 0 ]; + + if ( !elem ) { + return; + } + + // Support: IE <=11 only + // Running getBoundingClientRect on a + // disconnected node in IE throws an error + if ( !elem.getClientRects().length ) { + return { top: 0, left: 0 }; + } + + rect = elem.getBoundingClientRect(); + + // Make sure element is not hidden (display: none) + if ( rect.width || rect.height ) { + doc = elem.ownerDocument; + win = getWindow( doc ); + docElem = doc.documentElement; + + return { + top: rect.top + win.pageYOffset - docElem.clientTop, + left: rect.left + win.pageXOffset - docElem.clientLeft + }; + } + + // Return zeros for disconnected and hidden elements (gh-2310) + return rect; + }, + + position: function() { + if ( !this[ 0 ] ) { + return; + } + + var offsetParent, offset, + elem = this[ 0 ], + parentOffset = { top: 0, left: 0 }; + + // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, + // because it is its only offset parent + if ( jQuery.css( elem, "position" ) === "fixed" ) { + + // Assume getBoundingClientRect is there when computed position is fixed + offset = elem.getBoundingClientRect(); + + } else { + + // Get *real* offsetParent + offsetParent = this.offsetParent(); + + // Get correct offsets + offset = this.offset(); + if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) { + parentOffset = offsetParent.offset(); + } + + // Add offsetParent borders + parentOffset = { + top: parentOffset.top + jQuery.css( offsetParent[ 0 ], "borderTopWidth", true ), + left: parentOffset.left + jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true ) + }; + } + + // Subtract parent offsets and element margins + return { + top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ), + left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true ) + }; + }, + + // This method will return documentElement in the following cases: + // 1) For the element inside the iframe without offsetParent, this method will return + // documentElement of the parent window + // 2) For the hidden or detached element + // 3) For body or html element, i.e. in case of the html node - it will return itself + // + // but those exceptions were never presented as a real life use-cases + // and might be considered as more preferable results. + // + // This logic, however, is not guaranteed and can change at any point in the future + offsetParent: function() { + return this.map( function() { + var offsetParent = this.offsetParent; + + while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) { + offsetParent = offsetParent.offsetParent; + } + + return offsetParent || documentElement; + } ); + } +} ); + +// Create scrollLeft and scrollTop methods +jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) { + var top = "pageYOffset" === prop; + + jQuery.fn[ method ] = function( val ) { + return access( this, function( elem, method, val ) { + var win = getWindow( elem ); + + if ( val === undefined ) { + return win ? win[ prop ] : elem[ method ]; + } + + if ( win ) { + win.scrollTo( + !top ? val : win.pageXOffset, + top ? val : win.pageYOffset + ); + + } else { + elem[ method ] = val; + } + }, method, val, arguments.length ); + }; +} ); + +// Support: Safari <=7 - 9.1, Chrome <=37 - 49 +// Add the top/left cssHooks using jQuery.fn.position +// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 +// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347 +// getComputedStyle returns percent when specified for top/left/bottom/right; +// rather than make the css module depend on the offset module, just check for it here +jQuery.each( [ "top", "left" ], function( i, prop ) { + jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition, + function( elem, computed ) { + if ( computed ) { + computed = curCSS( elem, prop ); + + // If curCSS returns percentage, fallback to offset + return rnumnonpx.test( computed ) ? + jQuery( elem ).position()[ prop ] + "px" : + computed; + } + } + ); +} ); + + +// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods +jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { + jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, + function( defaultExtra, funcName ) { + + // Margin is only for outerHeight, outerWidth + jQuery.fn[ funcName ] = function( margin, value ) { + var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), + extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); + + return access( this, function( elem, type, value ) { + var doc; + + if ( jQuery.isWindow( elem ) ) { + + // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729) + return funcName.indexOf( "outer" ) === 0 ? + elem[ "inner" + name ] : + elem.document.documentElement[ "client" + name ]; + } + + // Get document width or height + if ( elem.nodeType === 9 ) { + doc = elem.documentElement; + + // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], + // whichever is greatest + return Math.max( + elem.body[ "scroll" + name ], doc[ "scroll" + name ], + elem.body[ "offset" + name ], doc[ "offset" + name ], + doc[ "client" + name ] + ); + } + + return value === undefined ? + + // Get width or height on the element, requesting but not forcing parseFloat + jQuery.css( elem, type, extra ) : + + // Set width or height on the element + jQuery.style( elem, type, value, extra ); + }, type, chainable ? margin : undefined, chainable ); + }; + } ); +} ); + + +jQuery.fn.extend( { + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length === 1 ? + this.off( selector, "**" ) : + this.off( types, selector || "**", fn ); + } +} ); + +jQuery.parseJSON = JSON.parse; + + + + +// Register as a named AMD module, since jQuery can be concatenated with other +// files that may use define, but not via a proper concatenation script that +// understands anonymous AMD modules. A named AMD is safest and most robust +// way to register. Lowercase jquery is used because AMD module names are +// derived from file names, and jQuery is normally delivered in a lowercase +// file name. Do this after creating the global so that if an AMD module wants +// to call noConflict to hide this version of jQuery, it will work. + +// Note that for maximum portability, libraries that are not jQuery should +// declare themselves as anonymous modules, and avoid setting a global if an +// AMD loader is present. jQuery is a special case. For more information, see +// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon + +if ( typeof define === "function" && define.amd ) { + define( "jquery", [], function() { + return jQuery; + } ); +} + + + + + +var + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$; + +jQuery.noConflict = function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; +}; + +// Expose jQuery and $ identifiers, even in AMD +// (#7102#comment:10, https://github.com/jquery/jquery/pull/557) +// and CommonJS for browser emulators (#13566) +if ( !noGlobal ) { + window.jQuery = window.$ = jQuery; +} + + +return jQuery; +} ); diff --git a/for_developers/SphinxDoc/_build/html/_static/jquery.js b/for_developers/SphinxDoc/_build/html/_static/jquery.js new file mode 100644 index 0000000..f6a6a99 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_static/jquery.js @@ -0,0 +1,4 @@ +/*! jQuery v3.1.0 | (c) jQuery Foundation | jquery.org/license */ +!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.1.0",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null!=a?a<0?this[a+this.length]:this[a]:f.call(this)},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c<b?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:h,sort:c.sort,splice:c.splice},r.extend=r.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||r.isFunction(g)||(g={}),h===i&&(g=this,h--);h<i;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(r.isPlainObject(d)||(e=r.isArray(d)))?(e?(e=!1,f=c&&r.isArray(c)?c:[]):f=c&&r.isPlainObject(c)?c:{},g[b]=r.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},r.extend({expando:"jQuery"+(q+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===r.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=r.type(a);return("number"===b||"string"===b)&&!isNaN(a-parseFloat(a))},isPlainObject:function(a){var b,c;return!(!a||"[object Object]"!==k.call(a))&&(!(b=e(a))||(c=l.call(b,"constructor")&&b.constructor,"function"==typeof c&&m.call(c)===n))},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?j[k.call(a)]||"object":typeof a},globalEval:function(a){p(a)},camelCase:function(a){return a.replace(t,"ms-").replace(u,v)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(w(a)){for(c=a.length;d<c;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(s,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(w(Object(a))?r.merge(c,"string"==typeof a?[a]:a):h.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:i.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;d<c;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;f<g;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,f=0,h=[];if(w(a))for(d=a.length;f<d;f++)e=b(a[f],f,c),null!=e&&h.push(e);else for(f in a)e=b(a[f],f,c),null!=e&&h.push(e);return g.apply([],h)},guid:1,proxy:function(a,b){var c,d,e;if("string"==typeof b&&(c=a[b],b=a,a=c),r.isFunction(a))return d=f.call(arguments,2),e=function(){return a.apply(b||this,d.concat(f.call(arguments)))},e.guid=a.guid=a.guid||r.guid++,e},now:Date.now,support:o}),"function"==typeof Symbol&&(r.fn[Symbol.iterator]=c[Symbol.iterator]),r.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){j["[object "+b+"]"]=b.toLowerCase()});function w(a){var b=!!a&&"length"in a&&a.length,c=r.type(a);return"function"!==c&&!r.isWindow(a)&&("array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",M="\\["+K+"*("+L+")(?:"+K+"*([*^$|!~]?=)"+K+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+L+"))|)"+K+"*\\]",N=":("+L+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+M+")*)|.*)\\)|)",O=new RegExp(K+"+","g"),P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"label"in b&&b.disabled===a||"form"in b&&b.disabled===a||"form"in b&&b.disabled===!1&&(b.isDisabled===a||b.isDisabled!==!a&&("label"in b||!ea(b))!==a)}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c<b;c+=2)a.push(c);return a}),odd:pa(function(a,b){for(var c=1;c<b;c+=2)a.push(c);return a}),lt:pa(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function ra(){}ra.prototype=d.filters=d.pseudos,d.setFilters=new ra,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=Q.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function sa(a){for(var b=0,c=a.length,d="";b<c;b++)d+=a[b].value;return d}function ta(a,b,c){var d=b.dir,e=b.next,f=e||d,g=c&&"parentNode"===f,h=x++;return b.first?function(b,c,e){while(b=b[d])if(1===b.nodeType||g)return a(b,c,e)}:function(b,c,i){var j,k,l,m=[w,h];if(i){while(b=b[d])if((1===b.nodeType||g)&&a(b,c,i))return!0}else while(b=b[d])if(1===b.nodeType||g)if(l=b[u]||(b[u]={}),k=l[b.uniqueID]||(l[b.uniqueID]={}),e&&e===b.nodeName.toLowerCase())b=b[d]||b;else{if((j=k[f])&&j[0]===w&&j[1]===h)return m[2]=j[2];if(k[f]=m,m[2]=a(b,c,i))return!0}}}function ua(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d<e;d++)ga(a,b[d],c);return c}function wa(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;h<i;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function xa(a,b,c,d,e,f){return d&&!d[u]&&(d=xa(d)),e&&!e[u]&&(e=xa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||va(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:wa(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=wa(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i<f;i++)if(c=d.relative[a[i].type])m=[ta(ua(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;e<f;e++)if(d.relative[a[e].type])break;return xa(i>1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i<e&&ya(a.slice(i,e)),e<f&&ya(a=a.slice(e)),e<f&&sa(a))}m.push(c)}return ua(m)}function za(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(_,aa),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=V.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(_,aa),$.test(j[0].type)&&qa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&sa(j),!a)return G.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||$.test(a)&&qa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext,B=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,C=/^.[^:#\[\.,]*$/;function D(a,b,c){if(r.isFunction(b))return r.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return r.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(C.test(b))return r.filter(b,a,c);b=r.filter(b,a)}return r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType})}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b<d;b++)if(r.contains(e[b],this))return!0}));for(c=this.pushStack([]),b=0;b<d;b++)r.find(a,e[b],c);return d>1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(D(this,a||[],!1))},not:function(a){return this.pushStack(D(this,a||[],!0))},is:function(a){return!!D(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var E,F=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,G=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||E,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:F.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),B.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};G.prototype=r.fn,E=r(d);var H=/^(?:parents|prev(?:Until|All))/,I={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a<c;a++)if(r.contains(this,b[a]))return!0})},closest:function(a,b){var c,d=0,e=this.length,f=[],g="string"!=typeof a&&r(a);if(!A.test(a))for(;d<e;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function J(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return J(a,"nextSibling")},prev:function(a){return J(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return a.contentDocument||r.merge([],a.childNodes)}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(I[a]||r.uniqueSort(e),H.test(a)&&e.reverse()),this.pushStack(e)}});var K=/\S+/g;function L(a){var b={};return r.each(a.match(K)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?L(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){r.each(b,function(b,c){r.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==r.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return r.each(arguments,function(a,b){var c;while((c=r.inArray(b,f,c))>-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function M(a){return a}function N(a){throw a}function O(a,b,c){var d;try{a&&r.isFunction(d=a.promise)?d.call(a).done(b).fail(c):a&&r.isFunction(d=a.then)?d.call(a,b,c):b.call(void 0,a)}catch(a){c.call(void 0,a)}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b<f)){if(a=d.apply(h,i),a===c.promise())throw new TypeError("Thenable self-resolution");j=a&&("object"==typeof a||"function"==typeof a)&&a.then,r.isFunction(j)?e?j.call(a,g(f,c,M,e),g(f,c,N,e)):(f++,j.call(a,g(f,c,M,e),g(f,c,N,e),g(f,c,M,c.notifyWith))):(d!==M&&(h=void 0,i=[a]),(e||c.resolveWith)(h,i))}},k=e?j:function(){try{j()}catch(a){r.Deferred.exceptionHook&&r.Deferred.exceptionHook(a,k.stackTrace),b+1>=f&&(d!==N&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:M,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:M)),c[2][3].add(g(0,a,r.isFunction(d)?d:N))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(O(a,g.done(h(c)).resolve,g.reject),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)O(e[c],h(c),g.reject);return g.promise()}});var P=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&P.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var Q=r.Deferred();r.fn.ready=function(a){return Q.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,holdReady:function(a){a?r.readyWait++:r.ready(!0)},ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||Q.resolveWith(d,[r]))}}),r.ready.then=Q.then;function R(){d.removeEventListener("DOMContentLoaded",R),a.removeEventListener("load",R),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",R),a.addEventListener("load",R));var S=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)S(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0, +r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h<i;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},T=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function U(){this.expando=r.expando+U.uid++}U.uid=1,U.prototype={cache:function(a){var b=a[this.expando];return b||(b={},T(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[r.camelCase(b)]=c;else for(d in b)e[r.camelCase(d)]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][r.camelCase(b)]},access:function(a,b,c){return void 0===b||b&&"string"==typeof b&&void 0===c?this.get(a,b):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d=a[this.expando];if(void 0!==d){if(void 0!==b){r.isArray(b)?b=b.map(r.camelCase):(b=r.camelCase(b),b=b in d?[b]:b.match(K)||[]),c=b.length;while(c--)delete d[b[c]]}(void 0===b||r.isEmptyObject(d))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!r.isEmptyObject(b)}};var V=new U,W=new U,X=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Y=/[A-Z]/g;function Z(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Y,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c||"false"!==c&&("null"===c?null:+c+""===c?+c:X.test(c)?JSON.parse(c):c)}catch(e){}W.set(a,b,c)}else c=void 0;return c}r.extend({hasData:function(a){return W.hasData(a)||V.hasData(a)},data:function(a,b,c){return W.access(a,b,c)},removeData:function(a,b){W.remove(a,b)},_data:function(a,b,c){return V.access(a,b,c)},_removeData:function(a,b){V.remove(a,b)}}),r.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=W.get(f),1===f.nodeType&&!V.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=r.camelCase(d.slice(5)),Z(f,d,e[d])));V.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){W.set(this,a)}):S(this,function(b){var c;if(f&&void 0===b){if(c=W.get(f,a),void 0!==c)return c;if(c=Z(f,a),void 0!==c)return c}else this.each(function(){W.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){W.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=V.get(a,b),c&&(!d||r.isArray(c)?d=V.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return V.get(a,c)||V.access(a,c,{empty:r.Callbacks("once memory").add(function(){V.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?r.queue(this[0],a):void 0===b?this:this.each(function(){var c=r.queue(this,a,b);r._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&r.dequeue(this,a)})},dequeue:function(a){return this.each(function(){r.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=r.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=V.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var $=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,_=new RegExp("^(?:([+-])=|)("+$+")([a-z%]*)$","i"),aa=["Top","Right","Bottom","Left"],ba=function(a,b){return a=b||a,"none"===a.style.display||""===a.style.display&&r.contains(a.ownerDocument,a)&&"none"===r.css(a,"display")},ca=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};function da(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return r.css(a,b,"")},i=h(),j=c&&c[3]||(r.cssNumber[b]?"":"px"),k=(r.cssNumber[b]||"px"!==j&&+i)&&_.exec(r.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,r.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var ea={};function fa(a){var b,c=a.ownerDocument,d=a.nodeName,e=ea[d];return e?e:(b=c.body.appendChild(c.createElement(d)),e=r.css(b,"display"),b.parentNode.removeChild(b),"none"===e&&(e="block"),ea[d]=e,e)}function ga(a,b){for(var c,d,e=[],f=0,g=a.length;f<g;f++)d=a[f],d.style&&(c=d.style.display,b?("none"===c&&(e[f]=V.get(d,"display")||null,e[f]||(d.style.display="")),""===d.style.display&&ba(d)&&(e[f]=fa(d))):"none"!==c&&(e[f]="none",V.set(d,"display",c)));for(f=0;f<g;f++)null!=e[f]&&(a[f].style.display=e[f]);return a}r.fn.extend({show:function(){return ga(this,!0)},hide:function(){return ga(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){ba(this)?r(this).show():r(this).hide()})}});var ha=/^(?:checkbox|radio)$/i,ia=/<([a-z][^\/\0>\x20\t\r\n\f]+)/i,ja=/^$|\/(?:java|ecma)script/i,ka={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ka.optgroup=ka.option,ka.tbody=ka.tfoot=ka.colgroup=ka.caption=ka.thead,ka.th=ka.td;function la(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&r.nodeName(a,b)?r.merge([a],c):c}function ma(a,b){for(var c=0,d=a.length;c<d;c++)V.set(a[c],"globalEval",!b||V.get(b[c],"globalEval"))}var na=/<|&#?\w+;/;function oa(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],n=0,o=a.length;n<o;n++)if(f=a[n],f||0===f)if("object"===r.type(f))r.merge(m,f.nodeType?[f]:f);else if(na.test(f)){g=g||l.appendChild(b.createElement("div")),h=(ia.exec(f)||["",""])[1].toLowerCase(),i=ka[h]||ka._default,g.innerHTML=i[1]+r.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;r.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",n=0;while(f=m[n++])if(d&&r.inArray(f,d)>-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=la(l.appendChild(f),"script"),j&&ma(g),c){k=0;while(f=g[k++])ja.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var pa=d.documentElement,qa=/^key/,ra=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,sa=/^([^.]*)(?:\.(.+)|)/;function ta(){return!0}function ua(){return!1}function va(){try{return d.activeElement}catch(a){}}function wa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)wa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=ua;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=V.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(pa,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(K)||[""],j=b.length;while(j--)h=sa.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=V.hasData(a)&&V.get(a);if(q&&(i=q.events)){b=(b||"").match(K)||[""],j=b.length;while(j--)if(h=sa.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&V.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(V.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c<arguments.length;c++)i[c]=arguments[c];if(b.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,b)!==!1){h=r.event.handlers.call(this,b,j),c=0;while((f=h[c++])&&!b.isPropagationStopped()){b.currentTarget=f.elem,d=0;while((g=f.handlers[d++])&&!b.isImmediatePropagationStopped())b.rnamespace&&!b.rnamespace.test(g.namespace)||(b.handleObj=g,b.data=g.data,e=((r.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(b.result=e)===!1&&(b.preventDefault(),b.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,b),b.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!==this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;c<h;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?r(e,this).index(i)>-1:r.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},addProp:function(a,b){Object.defineProperty(r.Event.prototype,a,{enumerable:!0,configurable:!0,get:r.isFunction(b)?function(){if(this.originalEvent)return b(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[a]},set:function(b){Object.defineProperty(this,a,{enumerable:!0,configurable:!0,writable:!0,value:b})}})},fix:function(a){return a[r.expando]?a:new r.Event(a)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==va()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===va()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&r.nodeName(this,"input"))return this.click(),!1},_default:function(a){return r.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}}},r.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)},r.Event=function(a,b){return this instanceof r.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ta:ua,this.target=a.target&&3===a.target.nodeType?a.target.parentNode:a.target,this.currentTarget=a.currentTarget,this.relatedTarget=a.relatedTarget):this.type=a,b&&r.extend(this,b),this.timeStamp=a&&a.timeStamp||r.now(),void(this[r.expando]=!0)):new r.Event(a,b)},r.Event.prototype={constructor:r.Event,isDefaultPrevented:ua,isPropagationStopped:ua,isImmediatePropagationStopped:ua,isSimulated:!1,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ta,a&&!this.isSimulated&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ta,a&&!this.isSimulated&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ta,a&&!this.isSimulated&&a.stopImmediatePropagation(),this.stopPropagation()}},r.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(a){var b=a.button;return null==a.which&&qa.test(a.type)?null!=a.charCode?a.charCode:a.keyCode:!a.which&&void 0!==b&&ra.test(a.type)?1&b?1:2&b?3:4&b?2:0:a.which}},r.event.addProp),r.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){r.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||r.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),r.fn.extend({on:function(a,b,c,d){return wa(this,a,b,c,d)},one:function(a,b,c,d){return wa(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,r(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=ua),this.each(function(){r.event.remove(this,a,c,b)})}});var xa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,ya=/<script|<style|<link/i,za=/checked\s*(?:[^=]|=\s*.checked.)/i,Aa=/^true\/(.*)/,Ba=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Ca(a,b){return r.nodeName(a,"table")&&r.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a:a}function Da(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ea(a){var b=Aa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Fa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(V.hasData(a)&&(f=V.access(a),g=V.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c<d;c++)r.event.add(b,e,j[e][c])}W.hasData(a)&&(h=W.access(a),i=r.extend({},h),W.set(b,i))}}function Ga(a,b){var c=b.nodeName.toLowerCase();"input"===c&&ha.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function Ha(a,b,c,d){b=g.apply([],b);var e,f,h,i,j,k,l=0,m=a.length,n=m-1,q=b[0],s=r.isFunction(q);if(s||m>1&&"string"==typeof q&&!o.checkClone&&za.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ha(f,b,c,d)});if(m&&(e=oa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(la(e,"script"),Da),i=h.length;l<m;l++)j=e,l!==n&&(j=r.clone(j,!0,!0),i&&r.merge(h,la(j,"script"))),c.call(a[l],j,l);if(i)for(k=h[h.length-1].ownerDocument,r.map(h,Ea),l=0;l<i;l++)j=h[l],ja.test(j.type||"")&&!V.access(j,"globalEval")&&r.contains(k,j)&&(j.src?r._evalUrl&&r._evalUrl(j.src):p(j.textContent.replace(Ba,""),k))}return a}function Ia(a,b,c){for(var d,e=b?r.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||r.cleanData(la(d)),d.parentNode&&(c&&r.contains(d.ownerDocument,d)&&ma(la(d,"script")),d.parentNode.removeChild(d));return a}r.extend({htmlPrefilter:function(a){return a.replace(xa,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=la(h),f=la(a),d=0,e=f.length;d<e;d++)Ga(f[d],g[d]);if(b)if(c)for(f=f||la(a),g=g||la(h),d=0,e=f.length;d<e;d++)Fa(f[d],g[d]);else Fa(a,h);return g=la(h,"script"),g.length>0&&ma(g,!i&&la(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(T(c)){if(b=c[V.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[V.expando]=void 0}c[W.expando]&&(c[W.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ia(this,a,!0)},remove:function(a){return Ia(this,a)},text:function(a){return S(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.appendChild(a)}})},prepend:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(la(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return S(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!ya.test(a)&&!ka[(ia.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c<d;c++)b=this[c]||{},1===b.nodeType&&(r.cleanData(la(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ha(this,arguments,function(b){var c=this.parentNode;r.inArray(this,a)<0&&(r.cleanData(la(this)),c&&c.replaceChild(b,this))},a)}}),r.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){r.fn[a]=function(a){for(var c,d=[],e=r(a),f=e.length-1,g=0;g<=f;g++)c=g===f?this:this.clone(!0),r(e[g])[b](c),h.apply(d,c.get());return this.pushStack(d)}});var Ja=/^margin/,Ka=new RegExp("^("+$+")(?!px)[a-z%]+$","i"),La=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)};!function(){function b(){if(i){i.style.cssText="box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",i.innerHTML="",pa.appendChild(h);var b=a.getComputedStyle(i);c="1%"!==b.top,g="2px"===b.marginLeft,e="4px"===b.width,i.style.marginRight="50%",f="4px"===b.marginRight,pa.removeChild(h),i=null}}var c,e,f,g,h=d.createElement("div"),i=d.createElement("div");i.style&&(i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",o.clearCloneStyle="content-box"===i.style.backgroundClip,h.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",h.appendChild(i),r.extend(o,{pixelPosition:function(){return b(),c},boxSizingReliable:function(){return b(),e},pixelMarginRight:function(){return b(),f},reliableMarginLeft:function(){return b(),g}}))}();function Ma(a,b,c){var d,e,f,g,h=a.style;return c=c||La(a),c&&(g=c.getPropertyValue(b)||c[b],""!==g||r.contains(a.ownerDocument,a)||(g=r.style(a,b)),!o.pixelMarginRight()&&Ka.test(g)&&Ja.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function Na(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Oa=/^(none|table(?!-c[ea]).+)/,Pa={position:"absolute",visibility:"hidden",display:"block"},Qa={letterSpacing:"0",fontWeight:"400"},Ra=["Webkit","Moz","ms"],Sa=d.createElement("div").style;function Ta(a){if(a in Sa)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ra.length;while(c--)if(a=Ra[c]+b,a in Sa)return a}function Ua(a,b,c){var d=_.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||"px"):b}function Va(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;f<4;f+=2)"margin"===c&&(g+=r.css(a,c+aa[f],!0,e)),d?("content"===c&&(g-=r.css(a,"padding"+aa[f],!0,e)),"margin"!==c&&(g-=r.css(a,"border"+aa[f]+"Width",!0,e))):(g+=r.css(a,"padding"+aa[f],!0,e),"padding"!==c&&(g+=r.css(a,"border"+aa[f]+"Width",!0,e)));return g}function Wa(a,b,c){var d,e=!0,f=La(a),g="border-box"===r.css(a,"boxSizing",!1,f);if(a.getClientRects().length&&(d=a.getBoundingClientRect()[b]),d<=0||null==d){if(d=Ma(a,b,f),(d<0||null==d)&&(d=a.style[b]),Ka.test(d))return d;e=g&&(o.boxSizingReliable()||d===a.style[b]),d=parseFloat(d)||0}return d+Va(a,b,c||(g?"border":"content"),e,f)+"px"}r.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Ma(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=r.camelCase(b),i=a.style;return b=r.cssProps[h]||(r.cssProps[h]=Ta(h)||h),g=r.cssHooks[b]||r.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=_.exec(c))&&e[1]&&(c=da(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(r.cssNumber[h]?"":"px")),o.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=r.camelCase(b);return b=r.cssProps[h]||(r.cssProps[h]=Ta(h)||h),g=r.cssHooks[b]||r.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Ma(a,b,d)),"normal"===e&&b in Qa&&(e=Qa[b]),""===c||c?(f=parseFloat(e),c===!0||isFinite(f)?f||0:e):e}}),r.each(["height","width"],function(a,b){r.cssHooks[b]={get:function(a,c,d){if(c)return!Oa.test(r.css(a,"display"))||a.getClientRects().length&&a.getBoundingClientRect().width?Wa(a,b,d):ca(a,Pa,function(){return Wa(a,b,d)})},set:function(a,c,d){var e,f=d&&La(a),g=d&&Va(a,b,d,"border-box"===r.css(a,"boxSizing",!1,f),f);return g&&(e=_.exec(c))&&"px"!==(e[3]||"px")&&(a.style[b]=c,c=r.css(a,b)),Ua(a,c,g)}}}),r.cssHooks.marginLeft=Na(o.reliableMarginLeft,function(a,b){if(b)return(parseFloat(Ma(a,"marginLeft"))||a.getBoundingClientRect().left-ca(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+"px"}),r.each({margin:"",padding:"",border:"Width"},function(a,b){r.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];d<4;d++)e[a+aa[d]+b]=f[d]||f[d-2]||f[0];return e}},Ja.test(a)||(r.cssHooks[a+b].set=Ua)}),r.fn.extend({css:function(a,b){return S(this,function(a,b,c){var d,e,f={},g=0;if(r.isArray(b)){for(d=La(a),e=b.length;g<e;g++)f[b[g]]=r.css(a,b[g],!1,d);return f}return void 0!==c?r.style(a,b,c):r.css(a,b)},a,b,arguments.length>1)}});function Xa(a,b,c,d,e){return new Xa.prototype.init(a,b,c,d,e)}r.Tween=Xa,Xa.prototype={constructor:Xa,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=Xa.propHooks[this.prop];return a&&a.get?a.get(this):Xa.propHooks._default.get(this)},run:function(a){var b,c=Xa.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Xa.propHooks._default.set(this),this}},Xa.prototype.init.prototype=Xa.prototype,Xa.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},Xa.propHooks.scrollTop=Xa.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=Xa.prototype.init,r.fx.step={};var Ya,Za,$a=/^(?:toggle|show|hide)$/,_a=/queueHooks$/;function ab(){Za&&(a.requestAnimationFrame(ab),r.fx.tick())}function bb(){return a.setTimeout(function(){Ya=void 0}),Ya=r.now()}function cb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=aa[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function db(a,b,c){for(var d,e=(gb.tweeners[b]||[]).concat(gb.tweeners["*"]),f=0,g=e.length;f<g;f++)if(d=e[f].call(c,b,a))return d}function eb(a,b,c){var d,e,f,g,h,i,j,k,l="width"in b||"height"in b,m=this,n={},o=a.style,p=a.nodeType&&ba(a),q=V.get(a,"fxshow");c.queue||(g=r._queueHooks(a,"fx"),null==g.unqueued&&(g.unqueued=0,h=g.empty.fire,g.empty.fire=function(){g.unqueued||h()}),g.unqueued++,m.always(function(){m.always(function(){g.unqueued--,r.queue(a,"fx").length||g.empty.fire()})}));for(d in b)if(e=b[d],$a.test(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}n[d]=q&&q[d]||r.style(a,d)}if(i=!r.isEmptyObject(b),i||!r.isEmptyObject(n)){l&&1===a.nodeType&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=q&&q.display,null==j&&(j=V.get(a,"display")),k=r.css(a,"display"),"none"===k&&(j?k=j:(ga([a],!0),j=a.style.display||j,k=r.css(a,"display"),ga([a]))),("inline"===k||"inline-block"===k&&null!=j)&&"none"===r.css(a,"float")&&(i||(m.done(function(){o.display=j}),null==j&&(k=o.display,j="none"===k?"":k)),o.display="inline-block")),c.overflow&&(o.overflow="hidden",m.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]})),i=!1;for(d in n)i||(q?"hidden"in q&&(p=q.hidden):q=V.access(a,"fxshow",{display:j}),f&&(q.hidden=!p),p&&ga([a],!0),m.done(function(){p||ga([a]),V.remove(a,"fxshow");for(d in n)r.style(a,d,n[d])})),i=db(p?q[d]:0,d,m),d in q||(q[d]=i.start,p&&(i.end=i.start,i.start=0))}}function fb(a,b){var c,d,e,f,g;for(c in a)if(d=r.camelCase(c),e=b[d],f=a[c],r.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=r.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function gb(a,b,c){var d,e,f=0,g=gb.prefilters.length,h=r.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Ya||bb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;g<i;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),f<1&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:r.extend({},b),opts:r.extend(!0,{specialEasing:{},easing:r.easing._default},c),originalProperties:b,originalOptions:c,startTime:Ya||bb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=r.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;c<d;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(fb(k,j.opts.specialEasing);f<g;f++)if(d=gb.prefilters[f].call(j,a,k,j.opts))return r.isFunction(d.stop)&&(r._queueHooks(j.elem,j.opts.queue).stop=r.proxy(d.stop,d)),d;return r.map(k,db,j),r.isFunction(j.opts.start)&&j.opts.start.call(a,j),r.fx.timer(r.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}r.Animation=r.extend(gb,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return da(c.elem,a,_.exec(b),c),c}]},tweener:function(a,b){r.isFunction(a)?(b=a,a=["*"]):a=a.match(K);for(var c,d=0,e=a.length;d<e;d++)c=a[d],gb.tweeners[c]=gb.tweeners[c]||[],gb.tweeners[c].unshift(b)},prefilters:[eb],prefilter:function(a,b){b?gb.prefilters.unshift(a):gb.prefilters.push(a)}}),r.speed=function(a,b,c){var e=a&&"object"==typeof a?r.extend({},a):{complete:c||!c&&b||r.isFunction(a)&&a,duration:a,easing:c&&b||b&&!r.isFunction(b)&&b};return r.fx.off||d.hidden?e.duration=0:e.duration="number"==typeof e.duration?e.duration:e.duration in r.fx.speeds?r.fx.speeds[e.duration]:r.fx.speeds._default,null!=e.queue&&e.queue!==!0||(e.queue="fx"),e.old=e.complete,e.complete=function(){r.isFunction(e.old)&&e.old.call(this),e.queue&&r.dequeue(this,e.queue)},e},r.fn.extend({fadeTo:function(a,b,c,d){return this.filter(ba).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=r.isEmptyObject(a),f=r.speed(b,c,d),g=function(){var b=gb(this,r.extend({},a),f);(e||V.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=r.timers,g=V.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&_a.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||r.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=V.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=r.timers,g=d?d.length:0;for(c.finish=!0,r.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;b<g;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),r.each(["toggle","show","hide"],function(a,b){var c=r.fn[b];r.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(cb(b,!0),a,d,e)}}),r.each({slideDown:cb("show"),slideUp:cb("hide"),slideToggle:cb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){r.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),r.timers=[],r.fx.tick=function(){var a,b=0,c=r.timers;for(Ya=r.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||r.fx.stop(),Ya=void 0},r.fx.timer=function(a){r.timers.push(a),a()?r.fx.start():r.timers.pop()},r.fx.interval=13,r.fx.start=function(){Za||(Za=a.requestAnimationFrame?a.requestAnimationFrame(ab):a.setInterval(r.fx.tick,r.fx.interval))},r.fx.stop=function(){a.cancelAnimationFrame?a.cancelAnimationFrame(Za):a.clearInterval(Za),Za=null},r.fx.speeds={slow:600,fast:200,_default:400},r.fn.delay=function(b,c){return b=r.fx?r.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement("input"),b=d.createElement("select"),c=b.appendChild(d.createElement("option"));a.type="checkbox",o.checkOn=""!==a.value,o.optSelected=c.selected,a=d.createElement("input"),a.value="t",a.type="radio",o.radioValue="t"===a.value}();var hb,ib=r.expr.attrHandle;r.fn.extend({attr:function(a,b){return S(this,r.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?hb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&r.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(K); +if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),hb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=ib[b]||r.find.attr;ib[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=ib[g],ib[g]=e,e=null!=c(a,b,d)?g:null,ib[g]=f),e}});var jb=/^(?:input|select|textarea|button)$/i,kb=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return S(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):jb.test(a.nodeName)||kb.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});var lb=/[\t\r\n\f]/g;function mb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,mb(this)))});if("string"==typeof a&&a){b=a.match(K)||[];while(c=this[i++])if(e=mb(c),d=1===c.nodeType&&(" "+e+" ").replace(lb," ")){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=r.trim(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,mb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(K)||[];while(c=this[i++])if(e=mb(c),d=1===c.nodeType&&(" "+e+" ").replace(lb," ")){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=r.trim(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,mb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(K)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=mb(this),b&&V.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":V.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+mb(c)+" ").replace(lb," ").indexOf(b)>-1)return!0;return!1}});var nb=/\r/g,ob=/[\x20\t\r\n\f]+/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":r.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(nb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:r.trim(r.text(a)).replace(ob," ")}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type,g=f?null:[],h=f?e+1:d.length,i=e<0?h:f?e:0;i<h;i++)if(c=d[i],(c.selected||i===e)&&!c.disabled&&(!c.parentNode.disabled||!r.nodeName(c.parentNode,"optgroup"))){if(b=r(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=r.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=r.inArray(r.valHooks.option.get(d),f)>-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(r.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var pb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!pb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,pb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(V.get(h,"events")||{})[b.type]&&V.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&T(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!T(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=V.access(d,b);e||d.addEventListener(a,c,!0),V.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=V.access(d,b)-1;e?V.access(d,b,e):(d.removeEventListener(a,c,!0),V.remove(d,b))}}});var qb=a.location,rb=r.now(),sb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var tb=/\[\]$/,ub=/\r?\n/g,vb=/^(?:submit|button|image|reset|file)$/i,wb=/^(?:input|select|textarea|keygen)/i;function xb(a,b,c,d){var e;if(r.isArray(b))r.each(b,function(b,e){c||tb.test(a)?d(a,e):xb(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)xb(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(r.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)xb(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&wb.test(this.nodeName)&&!vb.test(a)&&(this.checked||!ha.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:r.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(ub,"\r\n")}}):{name:b.name,value:c.replace(ub,"\r\n")}}).get()}});var yb=/%20/g,zb=/#.*$/,Ab=/([?&])_=[^&]*/,Bb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Cb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Db=/^(?:GET|HEAD)$/,Eb=/^\/\//,Fb={},Gb={},Hb="*/".concat("*"),Ib=d.createElement("a");Ib.href=qb.href;function Jb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(K)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Kb(a,b,c,d){var e={},f=a===Gb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Lb(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Mb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Nb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:qb.href,type:"GET",isLocal:Cb.test(qb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Hb,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"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Lb(Lb(a,r.ajaxSettings),b):Lb(r.ajaxSettings,a)},ajaxPrefilter:Jb(Fb),ajaxTransport:Jb(Gb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Bb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||qb.href)+"").replace(Eb,qb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(K)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Ib.protocol+"//"+Ib.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Kb(Fb,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Db.test(o.type),f=o.url.replace(zb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(yb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(sb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Ab,""),n=(sb.test(f)?"&":"?")+"_="+rb++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Hb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Kb(Gb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Mb(o,y,d)),v=Nb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Ob={0:200,1223:204},Pb=r.ajaxSettings.xhr();o.cors=!!Pb&&"withCredentials"in Pb,o.ajax=Pb=!!Pb,r.ajaxTransport(function(b){var c,d;if(o.cors||Pb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Ob[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r("<script>").prop({charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&f("error"===a.type?404:200,a.type)}),d.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Qb=[],Rb=/(=)\?(?=&|$)|\?\?/;r.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Qb.pop()||r.expando+"_"+rb++;return this[a]=!0,a}}),r.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Rb.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Rb.test(b.data)&&"data");if(h||"jsonp"===b.dataTypes[0])return e=b.jsonpCallback=r.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Rb,"$1"+e):b.jsonp!==!1&&(b.url+=(sb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||r.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?r(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Qb.push(e)),g&&r.isFunction(f)&&f(g[0]),g=f=void 0}),"script"}),o.createHTMLDocument=function(){var a=d.implementation.createHTMLDocument("").body;return a.innerHTML="<form></form><form></form>",2===a.childNodes.length}(),r.parseHTML=function(a,b,c){if("string"!=typeof a)return[];"boolean"==typeof b&&(c=b,b=!1);var e,f,g;return b||(o.createHTMLDocument?(b=d.implementation.createHTMLDocument(""),e=b.createElement("base"),e.href=d.location.href,b.head.appendChild(e)):b=d),f=B.exec(a),g=!c&&[],f?[b.createElement(f[1])]:(f=oa([a],b,g),g&&g.length&&r(g).remove(),r.merge([],f.childNodes))},r.fn.load=function(a,b,c){var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=r.trim(a.slice(h)),a=a.slice(0,h)),r.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&r.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?r("<div>").append(r.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},r.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){r.fn[b]=function(a){return this.on(b,a)}}),r.expr.pseudos.animated=function(a){return r.grep(r.timers,function(b){return a===b.elem}).length};function Sb(a){return r.isWindow(a)?a:9===a.nodeType&&a.defaultView}r.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=r.css(a,"position"),l=r(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=r.css(a,"top"),i=r.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),r.isFunction(b)&&(b=b.call(a,c,r.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},r.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){r.offset.setOffset(this,a,b)});var b,c,d,e,f=this[0];if(f)return f.getClientRects().length?(d=f.getBoundingClientRect(),d.width||d.height?(e=f.ownerDocument,c=Sb(e),b=e.documentElement,{top:d.top+c.pageYOffset-b.clientTop,left:d.left+c.pageXOffset-b.clientLeft}):d):{top:0,left:0}},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===r.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),r.nodeName(a[0],"html")||(d=a.offset()),d={top:d.top+r.css(a[0],"borderTopWidth",!0),left:d.left+r.css(a[0],"borderLeftWidth",!0)}),{top:b.top-d.top-r.css(c,"marginTop",!0),left:b.left-d.left-r.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&"static"===r.css(a,"position"))a=a.offsetParent;return a||pa})}}),r.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c="pageYOffset"===b;r.fn[a]=function(d){return S(this,function(a,d,e){var f=Sb(a);return void 0===e?f?f[b]:a[d]:void(f?f.scrollTo(c?f.pageXOffset:e,c?e:f.pageYOffset):a[d]=e)},a,d,arguments.length)}}),r.each(["top","left"],function(a,b){r.cssHooks[b]=Na(o.pixelPosition,function(a,c){if(c)return c=Ma(a,b),Ka.test(c)?r(a).position()[b]+"px":c})}),r.each({Height:"height",Width:"width"},function(a,b){r.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){r.fn[d]=function(e,f){var g=arguments.length&&(c||"boolean"!=typeof e),h=c||(e===!0||f===!0?"margin":"border");return S(this,function(b,c,e){var f;return r.isWindow(b)?0===d.indexOf("outer")?b["inner"+a]:b.document.documentElement["client"+a]:9===b.nodeType?(f=b.documentElement,Math.max(b.body["scroll"+a],f["scroll"+a],b.body["offset"+a],f["offset"+a],f["client"+a])):void 0===e?r.css(b,c,h):r.style(b,c,e,h)},b,g?e:void 0,g)}})}),r.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}}),r.parseJSON=JSON.parse,"function"==typeof define&&define.amd&&define("jquery",[],function(){return r});var Tb=a.jQuery,Ub=a.$;return r.noConflict=function(b){return a.$===r&&(a.$=Ub),b&&a.jQuery===r&&(a.jQuery=Tb),r},b||(a.jQuery=a.$=r),r}); diff --git a/for_developers/SphinxDoc/_build/html/_static/minus.png b/for_developers/SphinxDoc/_build/html/_static/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..d96755fdaf8bb2214971e0db9c1fd3077d7c419d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0y~yVBiK}4h9AWhMwaZzZe)86g^!WLn;`PEt(m4((N1$ qT5J54Rote=BCz_OtVqKR4hDwUH)%$B(trFwnmk?oT-G@yGywom%@%0@ literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/html/_static/plus.png b/for_developers/SphinxDoc/_build/html/_static/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..7107cec93a979b9a5f64843235a16651d563ce2d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0y~yVBiK}4h9AWhMwaZzZe)86g^!WLn;`PEt(m4((N1$ pT5Cj47Kj#R>InVM$K{a2!oZ-bm^kJ02L~3ACQnyCmvv4FO#meY6wUwu literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/html/_static/pygments.css b/for_developers/SphinxDoc/_build/html/_static/pygments.css new file mode 100644 index 0000000..20c4814 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_static/pygments.css @@ -0,0 +1,69 @@ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/html/_static/searchtools.js b/for_developers/SphinxDoc/_build/html/_static/searchtools.js new file mode 100644 index 0000000..41b8336 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_static/searchtools.js @@ -0,0 +1,761 @@ +/* + * searchtools.js_t + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + + +/* Non-minified version JS is _stemmer.js if file is provided */ +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + + + +/** + * Simple result scoring code. + */ +var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [filename, title, anchor, descr, score] + // and returns the new score. + /* + score: function(result) { + return result[4]; + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: {0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5}, // used to be unimportantResults + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + // query found in terms + term: 5 +}; + + + + + +var splitChars = (function() { + var result = {}; + var singles = [96, 180, 187, 191, 215, 247, 749, 885, 903, 907, 909, 930, 1014, 1648, + 1748, 1809, 2416, 2473, 2481, 2526, 2601, 2609, 2612, 2615, 2653, 2702, + 2706, 2729, 2737, 2740, 2857, 2865, 2868, 2910, 2928, 2948, 2961, 2971, + 2973, 3085, 3089, 3113, 3124, 3213, 3217, 3241, 3252, 3295, 3341, 3345, + 3369, 3506, 3516, 3633, 3715, 3721, 3736, 3744, 3748, 3750, 3756, 3761, + 3781, 3912, 4239, 4347, 4681, 4695, 4697, 4745, 4785, 4799, 4801, 4823, + 4881, 5760, 5901, 5997, 6313, 7405, 8024, 8026, 8028, 8030, 8117, 8125, + 8133, 8181, 8468, 8485, 8487, 8489, 8494, 8527, 11311, 11359, 11687, 11695, + 11703, 11711, 11719, 11727, 11735, 12448, 12539, 43010, 43014, 43019, 43587, + 43696, 43713, 64286, 64297, 64311, 64317, 64319, 64322, 64325, 65141]; + var i, j, start, end; + for (i = 0; i < singles.length; i++) { + result[singles[i]] = true; + } + var ranges = [[0, 47], [58, 64], [91, 94], [123, 169], [171, 177], [182, 184], [706, 709], + [722, 735], [741, 747], [751, 879], [888, 889], [894, 901], [1154, 1161], + [1318, 1328], [1367, 1368], [1370, 1376], [1416, 1487], [1515, 1519], [1523, 1568], + [1611, 1631], [1642, 1645], [1750, 1764], [1767, 1773], [1789, 1790], [1792, 1807], + [1840, 1868], [1958, 1968], [1970, 1983], [2027, 2035], [2038, 2041], [2043, 2047], + [2070, 2073], [2075, 2083], [2085, 2087], [2089, 2307], [2362, 2364], [2366, 2383], + [2385, 2391], [2402, 2405], [2419, 2424], [2432, 2436], [2445, 2446], [2449, 2450], + [2483, 2485], [2490, 2492], [2494, 2509], [2511, 2523], [2530, 2533], [2546, 2547], + [2554, 2564], [2571, 2574], [2577, 2578], [2618, 2648], [2655, 2661], [2672, 2673], + [2677, 2692], [2746, 2748], [2750, 2767], [2769, 2783], [2786, 2789], [2800, 2820], + [2829, 2830], [2833, 2834], [2874, 2876], [2878, 2907], [2914, 2917], [2930, 2946], + [2955, 2957], [2966, 2968], [2976, 2978], [2981, 2983], [2987, 2989], [3002, 3023], + [3025, 3045], [3059, 3076], [3130, 3132], [3134, 3159], [3162, 3167], [3170, 3173], + [3184, 3191], [3199, 3204], [3258, 3260], [3262, 3293], [3298, 3301], [3312, 3332], + [3386, 3388], [3390, 3423], [3426, 3429], [3446, 3449], [3456, 3460], [3479, 3481], + [3518, 3519], [3527, 3584], [3636, 3647], [3655, 3663], [3674, 3712], [3717, 3718], + [3723, 3724], [3726, 3731], [3752, 3753], [3764, 3772], [3774, 3775], [3783, 3791], + [3802, 3803], [3806, 3839], [3841, 3871], [3892, 3903], [3949, 3975], [3980, 4095], + [4139, 4158], [4170, 4175], [4182, 4185], [4190, 4192], [4194, 4196], [4199, 4205], + [4209, 4212], [4226, 4237], [4250, 4255], [4294, 4303], [4349, 4351], [4686, 4687], + [4702, 4703], [4750, 4751], [4790, 4791], [4806, 4807], [4886, 4887], [4955, 4968], + [4989, 4991], [5008, 5023], [5109, 5120], [5741, 5742], [5787, 5791], [5867, 5869], + [5873, 5887], [5906, 5919], [5938, 5951], [5970, 5983], [6001, 6015], [6068, 6102], + [6104, 6107], [6109, 6111], [6122, 6127], [6138, 6159], [6170, 6175], [6264, 6271], + [6315, 6319], [6390, 6399], [6429, 6469], [6510, 6511], [6517, 6527], [6572, 6592], + [6600, 6607], [6619, 6655], [6679, 6687], [6741, 6783], [6794, 6799], [6810, 6822], + [6824, 6916], [6964, 6980], [6988, 6991], [7002, 7042], [7073, 7085], [7098, 7167], + [7204, 7231], [7242, 7244], [7294, 7400], [7410, 7423], [7616, 7679], [7958, 7959], + [7966, 7967], [8006, 8007], [8014, 8015], [8062, 8063], [8127, 8129], [8141, 8143], + [8148, 8149], [8156, 8159], [8173, 8177], [8189, 8303], [8306, 8307], [8314, 8318], + [8330, 8335], [8341, 8449], [8451, 8454], [8456, 8457], [8470, 8472], [8478, 8483], + [8506, 8507], [8512, 8516], [8522, 8525], [8586, 9311], [9372, 9449], [9472, 10101], + [10132, 11263], [11493, 11498], [11503, 11516], [11518, 11519], [11558, 11567], + [11622, 11630], [11632, 11647], [11671, 11679], [11743, 11822], [11824, 12292], + [12296, 12320], [12330, 12336], [12342, 12343], [12349, 12352], [12439, 12444], + [12544, 12548], [12590, 12592], [12687, 12689], [12694, 12703], [12728, 12783], + [12800, 12831], [12842, 12880], [12896, 12927], [12938, 12976], [12992, 13311], + [19894, 19967], [40908, 40959], [42125, 42191], [42238, 42239], [42509, 42511], + [42540, 42559], [42592, 42593], [42607, 42622], [42648, 42655], [42736, 42774], + [42784, 42785], [42889, 42890], [42893, 43002], [43043, 43055], [43062, 43071], + [43124, 43137], [43188, 43215], [43226, 43249], [43256, 43258], [43260, 43263], + [43302, 43311], [43335, 43359], [43389, 43395], [43443, 43470], [43482, 43519], + [43561, 43583], [43596, 43599], [43610, 43615], [43639, 43641], [43643, 43647], + [43698, 43700], [43703, 43704], [43710, 43711], [43715, 43738], [43742, 43967], + [44003, 44015], [44026, 44031], [55204, 55215], [55239, 55242], [55292, 55295], + [57344, 63743], [64046, 64047], [64110, 64111], [64218, 64255], [64263, 64274], + [64280, 64284], [64434, 64466], [64830, 64847], [64912, 64913], [64968, 65007], + [65020, 65135], [65277, 65295], [65306, 65312], [65339, 65344], [65371, 65381], + [65471, 65473], [65480, 65481], [65488, 65489], [65496, 65497]]; + for (i = 0; i < ranges.length; i++) { + start = ranges[i][0]; + end = ranges[i][1]; + for (j = start; j <= end; j++) { + result[j] = true; + } + } + return result; +})(); + +function splitQuery(query) { + var result = []; + var start = -1; + for (var i = 0; i < query.length; i++) { + if (splitChars[query.charCodeAt(i)]) { + if (start !== -1) { + result.push(query.slice(start, i)); + start = -1; + } + } else if (start === -1) { + start = i; + } + } + if (start !== -1) { + result.push(query.slice(start)); + } + return result; +} + + + + +/** + * Search Module + */ +var Search = { + + _index : null, + _queued_query : null, + _pulse_status : -1, + + init : function() { + var params = $.getQueryParameters(); + if (params.q) { + var query = params.q[0]; + $('input[name="q"]')[0].value = query; + this.performSearch(query); + } + }, + + loadIndex : function(url) { + $.ajax({type: "GET", url: url, data: null, + dataType: "script", cache: true, + complete: function(jqxhr, textstatus) { + if (textstatus != "success") { + document.getElementById("searchindexloader").src = url; + } + }}); + }, + + setIndex : function(index) { + var q; + this._index = index; + if ((q = this._queued_query) !== null) { + this._queued_query = null; + Search.query(q); + } + }, + + hasIndex : function() { + return this._index !== null; + }, + + deferQuery : function(query) { + this._queued_query = query; + }, + + stopPulse : function() { + this._pulse_status = 0; + }, + + startPulse : function() { + if (this._pulse_status >= 0) + return; + function pulse() { + var i; + Search._pulse_status = (Search._pulse_status + 1) % 4; + var dotString = ''; + for (i = 0; i < Search._pulse_status; i++) + dotString += '.'; + Search.dots.text(dotString); + if (Search._pulse_status > -1) + window.setTimeout(pulse, 500); + } + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch : function(query) { + // create the required interface elements + this.out = $('#search-results'); + this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out); + this.dots = $('<span></span>').appendTo(this.title); + this.status = $('<p style="display: none"></p>').appendTo(this.out); + this.output = $('<ul class="search"/>').appendTo(this.out); + + $('#search-progress').text(_('Preparing search...')); + this.startPulse(); + + // index already loaded, the browser was quick! + if (this.hasIndex()) + this.query(query); + else + this.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query : function(query) { + var i; + var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"]; + + // stem the searchterms and add them to the correct list + var stemmer = new Stemmer(); + var searchterms = []; + var excluded = []; + var hlterms = []; + var tmp = splitQuery(query); + var objectterms = []; + for (i = 0; i < tmp.length; i++) { + if (tmp[i] !== "") { + objectterms.push(tmp[i].toLowerCase()); + } + + if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) || + tmp[i] === "") { + // skip this "word" + continue; + } + // stem the word + var word = stemmer.stemWord(tmp[i].toLowerCase()); + // prevent stemmer from cutting word smaller than two chars + if(word.length < 3 && tmp[i].length >= 3) { + word = tmp[i]; + } + var toAppend; + // select the correct list + if (word[0] == '-') { + toAppend = excluded; + word = word.substr(1); + } + else { + toAppend = searchterms; + hlterms.push(tmp[i].toLowerCase()); + } + // only add if not already in the list + if (!$u.contains(toAppend, word)) + toAppend.push(word); + } + var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" ")); + + // console.debug('SEARCH: searching for:'); + // console.info('required: ', searchterms); + // console.info('excluded: ', excluded); + + // prepare search + var terms = this._index.terms; + var titleterms = this._index.titleterms; + + // array of [filename, title, anchor, descr, score] + var results = []; + $('#search-progress').empty(); + + // lookup as object + for (i = 0; i < objectterms.length; i++) { + var others = [].concat(objectterms.slice(0, i), + objectterms.slice(i+1, objectterms.length)); + results = results.concat(this.performObjectSearch(objectterms[i], others)); + } + + // lookup as search terms in fulltext + results = results.concat(this.performTermsSearch(searchterms, excluded, terms, titleterms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + for (i = 0; i < results.length; i++) + results[i][4] = Scorer.score(results[i]); + } + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort(function(a, b) { + var left = a[4]; + var right = b[4]; + if (left > right) { + return 1; + } else if (left < right) { + return -1; + } else { + // same score: sort alphabetically + left = a[1].toLowerCase(); + right = b[1].toLowerCase(); + return (left > right) ? -1 : ((left < right) ? 1 : 0); + } + }); + + // for debugging + //Search.lastresults = results.slice(); // a copy + //console.info('search results:', Search.lastresults); + + // print the results + var resultCount = results.length; + function displayNextItem() { + // results left, load the summary and display it + if (results.length) { + var item = results.pop(); + var listItem = $('<li style="display:none"></li>'); + if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') { + // dirhtml builder + var dirname = item[0] + '/'; + if (dirname.match(/\/index\/$/)) { + dirname = dirname.substring(0, dirname.length-6); + } else if (dirname == 'index/') { + dirname = ''; + } + listItem.append($('<a/>').attr('href', + DOCUMENTATION_OPTIONS.URL_ROOT + dirname + + highlightstring + item[2]).html(item[1])); + } else { + // normal html builders + listItem.append($('<a/>').attr('href', + item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX + + highlightstring + item[2]).html(item[1])); + } + if (item[3]) { + listItem.append($('<span> (' + item[3] + ')</span>')); + Search.output.append(listItem); + listItem.slideDown(5, function() { + displayNextItem(); + }); + } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) { + var suffix = DOCUMENTATION_OPTIONS.SOURCELINK_SUFFIX; + if (suffix === undefined) { + suffix = '.txt'; + } + $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[5] + (item[5].slice(-suffix.length) === suffix ? '' : suffix), + dataType: "text", + complete: function(jqxhr, textstatus) { + var data = jqxhr.responseText; + if (data !== '' && data !== undefined) { + listItem.append(Search.makeSearchSummary(data, searchterms, hlterms)); + } + Search.output.append(listItem); + listItem.slideDown(5, function() { + displayNextItem(); + }); + }}); + } else { + // no source available, just display title + Search.output.append(listItem); + listItem.slideDown(5, function() { + displayNextItem(); + }); + } + } + // search finished, update title and status message + else { + Search.stopPulse(); + Search.title.text(_('Search Results')); + if (!resultCount) + Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.')); + else + Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount)); + Search.status.fadeIn(500); + } + } + displayNextItem(); + }, + + /** + * search for object names + */ + performObjectSearch : function(object, otherterms) { + var filenames = this._index.filenames; + var docnames = this._index.docnames; + var objects = this._index.objects; + var objnames = this._index.objnames; + var titles = this._index.titles; + + var i; + var results = []; + + for (var prefix in objects) { + for (var name in objects[prefix]) { + var fullname = (prefix ? prefix + '.' : '') + name; + if (fullname.toLowerCase().indexOf(object) > -1) { + var score = 0; + var parts = fullname.split('.'); + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullname == object || parts[parts.length - 1] == object) { + score += Scorer.objNameMatch; + // matches in last name + } else if (parts[parts.length - 1].indexOf(object) > -1) { + score += Scorer.objPartialMatch; + } + var match = objects[prefix][name]; + var objname = objnames[match[1]][2]; + var title = titles[match[0]]; + // If more than one term searched for, we require other words to be + // found in the name/title/description + if (otherterms.length > 0) { + var haystack = (prefix + ' ' + name + ' ' + + objname + ' ' + title).toLowerCase(); + var allfound = true; + for (i = 0; i < otherterms.length; i++) { + if (haystack.indexOf(otherterms[i]) == -1) { + allfound = false; + break; + } + } + if (!allfound) { + continue; + } + } + var descr = objname + _(', in ') + title; + + var anchor = match[3]; + if (anchor === '') + anchor = fullname; + else if (anchor == '-') + anchor = objnames[match[1]][1] + '-' + fullname; + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) { + score += Scorer.objPrio[match[2]]; + } else { + score += Scorer.objPrioDefault; + } + results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]); + } + } + } + + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch : function(searchterms, excluded, terms, titleterms) { + var docnames = this._index.docnames; + var filenames = this._index.filenames; + var titles = this._index.titles; + + var i, j, file; + var fileMap = {}; + var scoreMap = {}; + var results = []; + + // perform the search on the required terms + for (i = 0; i < searchterms.length; i++) { + var word = searchterms[i]; + var files = []; + var _o = [ + {files: terms[word], score: Scorer.term}, + {files: titleterms[word], score: Scorer.title} + ]; + + // no match but word was a required one + if ($u.every(_o, function(o){return o.files === undefined;})) { + break; + } + // found search word in contents + $u.each(_o, function(o) { + var _files = o.files; + if (_files === undefined) + return + + if (_files.length === undefined) + _files = [_files]; + files = files.concat(_files); + + // set score for the word in each file to Scorer.term + for (j = 0; j < _files.length; j++) { + file = _files[j]; + if (!(file in scoreMap)) + scoreMap[file] = {} + scoreMap[file][word] = o.score; + } + }); + + // create the mapping + for (j = 0; j < files.length; j++) { + file = files[j]; + if (file in fileMap) + fileMap[file].push(word); + else + fileMap[file] = [word]; + } + } + + // now check if the files don't contain excluded terms + for (file in fileMap) { + var valid = true; + + // check if all requirements are matched + if (fileMap[file].length != searchterms.length) + continue; + + // ensure that none of the excluded terms is in the search result + for (i = 0; i < excluded.length; i++) { + if (terms[excluded[i]] == file || + titleterms[excluded[i]] == file || + $u.contains(terms[excluded[i]] || [], file) || + $u.contains(titleterms[excluded[i]] || [], file)) { + valid = false; + break; + } + } + + // if we have still a valid result we can add it to the result list + if (valid) { + // select one (max) score for the file. + // for better ranking, we should calculate ranking by using words statistics like basic tf-idf... + var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]})); + results.push([docnames[file], titles[file], '', null, score, filenames[file]]); + } + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words, hlwords is the list of normal, unstemmed + * words. the first one is used to find the occurrence, the + * latter for highlighting it. + */ + makeSearchSummary : function(text, keywords, hlwords) { + var textLower = text.toLowerCase(); + var start = 0; + $.each(keywords, function() { + var i = textLower.indexOf(this.toLowerCase()); + if (i > -1) + start = i; + }); + start = Math.max(start - 120, 0); + var excerpt = ((start > 0) ? '...' : '') + + $.trim(text.substr(start, 240)) + + ((start + 240 - text.length) ? '...' : ''); + var rv = $('<div class="context"></div>').text(excerpt); + $.each(hlwords, function() { + rv = rv.highlightText(this, 'highlighted'); + }); + return rv; + } +}; + +$(document).ready(function() { + Search.init(); +}); \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/html/_static/sidebar.js b/for_developers/SphinxDoc/_build/html/_static/sidebar.js new file mode 100644 index 0000000..dfbfb05 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_static/sidebar.js @@ -0,0 +1,159 @@ +/* + * sidebar.js + * ~~~~~~~~~~ + * + * This script makes the Sphinx sidebar collapsible. + * + * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds + * in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton + * used to collapse and expand the sidebar. + * + * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden + * and the width of the sidebar and the margin-left of the document + * are decreased. When the sidebar is expanded the opposite happens. + * This script saves a per-browser/per-session cookie used to + * remember the position of the sidebar among the pages. + * Once the browser is closed the cookie is deleted and the position + * reset to the default (expanded). + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +$(function() { + + + + + + + + + // global elements used by the functions. + // the 'sidebarbutton' element is defined as global after its + // creation, in the add_sidebar_button function + var bodywrapper = $('.bodywrapper'); + var sidebar = $('.sphinxsidebar'); + var sidebarwrapper = $('.sphinxsidebarwrapper'); + + // for some reason, the document has no sidebar; do not run into errors + if (!sidebar.length) return; + + // original margin-left of the bodywrapper and width of the sidebar + // with the sidebar expanded + var bw_margin_expanded = bodywrapper.css('margin-left'); + var ssb_width_expanded = sidebar.width(); + + // margin-left of the bodywrapper and width of the sidebar + // with the sidebar collapsed + var bw_margin_collapsed = '.8em'; + var ssb_width_collapsed = '.8em'; + + // colors used by the current theme + var dark_color = $('.related').css('background-color'); + var light_color = $('.document').css('background-color'); + + function sidebar_is_collapsed() { + return sidebarwrapper.is(':not(:visible)'); + } + + function toggle_sidebar() { + if (sidebar_is_collapsed()) + expand_sidebar(); + else + collapse_sidebar(); + } + + function collapse_sidebar() { + sidebarwrapper.hide(); + sidebar.css('width', ssb_width_collapsed); + bodywrapper.css('margin-left', bw_margin_collapsed); + sidebarbutton.css({ + 'margin-left': '0', + 'height': bodywrapper.height() + }); + sidebarbutton.find('span').text('»'); + sidebarbutton.attr('title', _('Expand sidebar')); + document.cookie = 'sidebar=collapsed'; + } + + function expand_sidebar() { + bodywrapper.css('margin-left', bw_margin_expanded); + sidebar.css('width', ssb_width_expanded); + sidebarwrapper.show(); + sidebarbutton.css({ + 'margin-left': ssb_width_expanded-12, + 'height': bodywrapper.height() + }); + sidebarbutton.find('span').text('«'); + sidebarbutton.attr('title', _('Collapse sidebar')); + document.cookie = 'sidebar=expanded'; + } + + function add_sidebar_button() { + sidebarwrapper.css({ + 'float': 'left', + 'margin-right': '0', + 'width': ssb_width_expanded - 28 + }); + // create the button + sidebar.append( + '<div id="sidebarbutton"><span>«</span></div>' + ); + var sidebarbutton = $('#sidebarbutton'); + light_color = sidebarbutton.css('background-color'); + // find the height of the viewport to center the '<<' in the page + var viewport_height; + if (window.innerHeight) + viewport_height = window.innerHeight; + else + viewport_height = $(window).height(); + sidebarbutton.find('span').css({ + 'display': 'block', + 'margin-top': (viewport_height - sidebar.position().top - 20) / 2 + }); + + sidebarbutton.click(toggle_sidebar); + sidebarbutton.attr('title', _('Collapse sidebar')); + sidebarbutton.css({ + 'color': '#FFFFFF', + 'border-left': '1px solid ' + dark_color, + 'font-size': '1.2em', + 'cursor': 'pointer', + 'height': bodywrapper.height(), + 'padding-top': '1px', + 'margin-left': ssb_width_expanded - 12 + }); + + sidebarbutton.hover( + function () { + $(this).css('background-color', dark_color); + }, + function () { + $(this).css('background-color', light_color); + } + ); + } + + function set_position_from_cookie() { + if (!document.cookie) + return; + var items = document.cookie.split(';'); + for(var k=0; k<items.length; k++) { + var key_val = items[k].split('='); + var key = key_val[0].replace(/ /, ""); // strip leading spaces + if (key == 'sidebar') { + var value = key_val[1]; + if ((value == 'collapsed') && (!sidebar_is_collapsed())) + collapse_sidebar(); + else if ((value == 'expanded') && (sidebar_is_collapsed())) + expand_sidebar(); + } + } + } + + add_sidebar_button(); + var sidebarbutton = $('#sidebarbutton'); + set_position_from_cookie(); +}); \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/html/_static/underscore-1.3.1.js b/for_developers/SphinxDoc/_build/html/_static/underscore-1.3.1.js new file mode 100644 index 0000000..208d4cd --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_static/underscore-1.3.1.js @@ -0,0 +1,999 @@ +// Underscore.js 1.3.1 +// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore + +(function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `global` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Establish the object that gets returned to break out of a loop iteration. + var breaker = {}; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var slice = ArrayProto.slice, + unshift = ArrayProto.unshift, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeForEach = ArrayProto.forEach, + nativeMap = ArrayProto.map, + nativeReduce = ArrayProto.reduce, + nativeReduceRight = ArrayProto.reduceRight, + nativeFilter = ArrayProto.filter, + nativeEvery = ArrayProto.every, + nativeSome = ArrayProto.some, + nativeIndexOf = ArrayProto.indexOf, + nativeLastIndexOf = ArrayProto.lastIndexOf, + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { return new wrapper(obj); }; + + // Export the Underscore object for **Node.js**, with + // backwards-compatibility for the old `require()` API. If we're in + // the browser, add `_` as a global object via a string identifier, + // for Closure Compiler "advanced" mode. + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } else { + root['_'] = _; + } + + // Current version. + _.VERSION = '1.3.1'; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles objects with the built-in `forEach`, arrays, and raw objects. + // Delegates to **ECMAScript 5**'s native `forEach` if available. + var each = _.each = _.forEach = function(obj, iterator, context) { + if (obj == null) return; + if (nativeForEach && obj.forEach === nativeForEach) { + obj.forEach(iterator, context); + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; + } + } else { + for (var key in obj) { + if (_.has(obj, key)) { + if (iterator.call(context, obj[key], key, obj) === breaker) return; + } + } + } + }; + + // Return the results of applying the iterator to each element. + // Delegates to **ECMAScript 5**'s native `map` if available. + _.map = _.collect = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); + each(obj, function(value, index, list) { + results[results.length] = iterator.call(context, value, index, list); + }); + if (obj.length === +obj.length) results.length = obj.length; + return results; + }; + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. + _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduce && obj.reduce === nativeReduce) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); + } + each(obj, function(value, index, list) { + if (!initial) { + memo = value; + initial = true; + } else { + memo = iterator.call(context, memo, value, index, list); + } + }); + if (!initial) throw new TypeError('Reduce of empty array with no initial value'); + return memo; + }; + + // The right-associative version of reduce, also known as `foldr`. + // Delegates to **ECMAScript 5**'s native `reduceRight` if available. + _.reduceRight = _.foldr = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); + } + var reversed = _.toArray(obj).reverse(); + if (context && !initial) iterator = _.bind(iterator, context); + return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator); + }; + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, iterator, context) { + var result; + any(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) { + result = value; + return true; + } + }); + return result; + }; + + // Return all the elements that pass a truth test. + // Delegates to **ECMAScript 5**'s native `filter` if available. + // Aliased as `select`. + _.filter = _.select = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); + each(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + each(obj, function(value, index, list) { + if (!iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Determine whether all of the elements match a truth test. + // Delegates to **ECMAScript 5**'s native `every` if available. + // Aliased as `all`. + _.every = _.all = function(obj, iterator, context) { + var result = true; + if (obj == null) return result; + if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); + each(obj, function(value, index, list) { + if (!(result = result && iterator.call(context, value, index, list))) return breaker; + }); + return result; + }; + + // Determine if at least one element in the object matches a truth test. + // Delegates to **ECMAScript 5**'s native `some` if available. + // Aliased as `any`. + var any = _.some = _.any = function(obj, iterator, context) { + iterator || (iterator = _.identity); + var result = false; + if (obj == null) return result; + if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); + each(obj, function(value, index, list) { + if (result || (result = iterator.call(context, value, index, list))) return breaker; + }); + return !!result; + }; + + // Determine if a given value is included in the array or object using `===`. + // Aliased as `contains`. + _.include = _.contains = function(obj, target) { + var found = false; + if (obj == null) return found; + if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; + found = any(obj, function(value) { + return value === target; + }); + return found; + }; + + // Invoke a method (with arguments) on every item in a collection. + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + return _.map(obj, function(value) { + return (_.isFunction(method) ? method || value : value[method]).apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, function(value){ return value[key]; }); + }; + + // Return the maximum element or (element-based computation). + _.max = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj); + if (!iterator && _.isEmpty(obj)) return -Infinity; + var result = {computed : -Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed >= result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj); + if (!iterator && _.isEmpty(obj)) return Infinity; + var result = {computed : Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed < result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + // Shuffle an array. + _.shuffle = function(obj) { + var shuffled = [], rand; + each(obj, function(value, index, list) { + if (index == 0) { + shuffled[0] = value; + } else { + rand = Math.floor(Math.random() * (index + 1)); + shuffled[index] = shuffled[rand]; + shuffled[rand] = value; + } + }); + return shuffled; + }; + + // Sort the object's values by a criterion produced by an iterator. + _.sortBy = function(obj, iterator, context) { + return _.pluck(_.map(obj, function(value, index, list) { + return { + value : value, + criteria : iterator.call(context, value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }), 'value'); + }; + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + _.groupBy = function(obj, val) { + var result = {}; + var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; }; + each(obj, function(value, index) { + var key = iterator(value, index); + (result[key] || (result[key] = [])).push(value); + }); + return result; + }; + + // Use a comparator function to figure out at what index an object should + // be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iterator) { + iterator || (iterator = _.identity); + var low = 0, high = array.length; + while (low < high) { + var mid = (low + high) >> 1; + iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; + } + return low; + }; + + // Safely convert anything iterable into a real, live array. + _.toArray = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) return iterable.toArray(); + if (_.isArray(iterable)) return slice.call(iterable); + if (_.isArguments(iterable)) return slice.call(iterable); + return _.values(iterable); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + return _.toArray(obj).length; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head`. The **guard** check allows it to work + // with `_.map`. + _.first = _.head = function(array, n, guard) { + return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; + }; + + // Returns everything but the last entry of the array. Especcialy useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. The **guard** check allows it to work with + // `_.map`. + _.initial = function(array, n, guard) { + return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); + }; + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. The **guard** check allows it to work with `_.map`. + _.last = function(array, n, guard) { + if ((n != null) && !guard) { + return slice.call(array, Math.max(array.length - n, 0)); + } else { + return array[array.length - 1]; + } + }; + + // Returns everything but the first entry of the array. Aliased as `tail`. + // Especially useful on the arguments object. Passing an **index** will return + // the rest of the values in the array from that index onward. The **guard** + // check allows it to work with `_.map`. + _.rest = _.tail = function(array, index, guard) { + return slice.call(array, (index == null) || guard ? 1 : index); + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, function(value){ return !!value; }); + }; + + // Return a completely flattened version of an array. + _.flatten = function(array, shallow) { + return _.reduce(array, function(memo, value) { + if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value)); + memo[memo.length] = value; + return memo; + }, []); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted, iterator) { + var initial = iterator ? _.map(array, iterator) : array; + var result = []; + _.reduce(initial, function(memo, el, i) { + if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) { + memo[memo.length] = el; + result[result.length] = array[i]; + } + return memo; + }, []); + return result; + }; + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + _.union = function() { + return _.uniq(_.flatten(arguments, true)); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. (Aliased as "intersect" for back-compat.) + _.intersection = _.intersect = function(array) { + var rest = slice.call(arguments, 1); + return _.filter(_.uniq(array), function(item) { + return _.every(rest, function(other) { + return _.indexOf(other, item) >= 0; + }); + }); + }; + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + _.difference = function(array) { + var rest = _.flatten(slice.call(arguments, 1)); + return _.filter(array, function(value){ return !_.include(rest, value); }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + var args = slice.call(arguments); + var length = _.max(_.pluck(args, 'length')); + var results = new Array(length); + for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i); + return results; + }; + + // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), + // we need this function. Return the position of the first occurrence of an + // item in an array, or -1 if the item is not included in the array. + // Delegates to **ECMAScript 5**'s native `indexOf` if available. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = function(array, item, isSorted) { + if (array == null) return -1; + var i, l; + if (isSorted) { + i = _.sortedIndex(array, item); + return array[i] === item ? i : -1; + } + if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); + for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i; + return -1; + }; + + // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. + _.lastIndexOf = function(array, item) { + if (array == null) return -1; + if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); + var i = array.length; + while (i--) if (i in array && array[i] === item) return i; + return -1; + }; + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (arguments.length <= 1) { + stop = start || 0; + start = 0; + } + step = arguments[2] || 1; + + var len = Math.max(Math.ceil((stop - start) / step), 0); + var idx = 0; + var range = new Array(len); + + while(idx < len) { + range[idx++] = start; + start += step; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Reusable constructor function for prototype setting. + var ctor = function(){}; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Binding with arguments is also known as `curry`. + // Delegates to **ECMAScript 5**'s native `Function.bind` if available. + // We check for `func.bind` first, to fail fast when `func` is undefined. + _.bind = function bind(func, context) { + var bound, args; + if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError; + args = slice.call(arguments, 2); + return bound = function() { + if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); + ctor.prototype = func.prototype; + var self = new ctor; + var result = func.apply(self, args.concat(slice.call(arguments))); + if (Object(result) === result) return result; + return self; + }; + }; + + // Bind all of an object's methods to that object. Useful for ensuring that + // all callbacks defined on an object belong to it. + _.bindAll = function(obj) { + var funcs = slice.call(arguments, 1); + if (funcs.length == 0) funcs = _.functions(obj); + each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memo = {}; + hasher || (hasher = _.identity); + return function() { + var key = hasher.apply(this, arguments); + return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); + }; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ return func.apply(func, args); }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = function(func) { + return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); + }; + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. + _.throttle = function(func, wait) { + var context, args, timeout, throttling, more; + var whenDone = _.debounce(function(){ more = throttling = false; }, wait); + return function() { + context = this; args = arguments; + var later = function() { + timeout = null; + if (more) func.apply(context, args); + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + func.apply(context, args); + } + whenDone(); + throttling = true; + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. + _.debounce = function(func, wait) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + func.apply(context, args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = function(func) { + var ran = false, memo; + return function() { + if (ran) return memo; + ran = true; + return memo = func.apply(this, arguments); + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return function() { + var args = [func].concat(slice.call(arguments, 0)); + return wrapper.apply(this, args); + }; + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var funcs = arguments; + return function() { + var args = arguments; + for (var i = funcs.length - 1; i >= 0; i--) { + args = [funcs[i].apply(this, args)]; + } + return args[0]; + }; + }; + + // Returns a function that will only be executed after being called N times. + _.after = function(times, func) { + if (times <= 0) return func(); + return function() { + if (--times < 1) { return func.apply(this, arguments); } + }; + }; + + // Object Functions + // ---------------- + + // Retrieve the names of an object's properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = nativeKeys || function(obj) { + if (obj !== Object(obj)) throw new TypeError('Invalid object'); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + return _.map(obj, _.identity); + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Fill in a given object with default properties. + _.defaults = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + if (obj[prop] == null) obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Internal recursive comparison function. + function eq(a, b, stack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. + if (a === b) return a !== 0 || 1 / a == 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) return a === b; + // Unwrap any wrapped objects. + if (a._chain) a = a._wrapped; + if (b._chain) b = b._wrapped; + // Invoke a custom `isEqual` method if one is provided. + if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b); + if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a); + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className != toString.call(b)) return false; + switch (className) { + // Strings, numbers, dates, and booleans are compared by value. + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return a == String(b); + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for + // other numeric values. + return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a == +b; + // RegExps are compared by their source patterns and flags. + case '[object RegExp]': + return a.source == b.source && + a.global == b.global && + a.multiline == b.multiline && + a.ignoreCase == b.ignoreCase; + } + if (typeof a != 'object' || typeof b != 'object') return false; + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + var length = stack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (stack[length] == a) return true; + } + // Add the first object to the stack of traversed objects. + stack.push(a); + var size = 0, result = true; + // Recursively compare objects and arrays. + if (className == '[object Array]') { + // Compare array lengths to determine if a deep comparison is necessary. + size = a.length; + result = size == b.length; + if (result) { + // Deep compare the contents, ignoring non-numeric properties. + while (size--) { + // Ensure commutative equality for sparse arrays. + if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break; + } + } + } else { + // Objects with different constructors are not equivalent. + if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false; + // Deep compare objects. + for (var key in a) { + if (_.has(a, key)) { + // Count the expected number of properties. + size++; + // Deep compare each member. + if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break; + } + } + // Ensure that both objects contain the same number of properties. + if (result) { + for (key in b) { + if (_.has(b, key) && !(size--)) break; + } + result = !size; + } + } + // Remove the first object from the stack of traversed objects. + stack.pop(); + return result; + } + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + return eq(a, b, []); + }; + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + _.isEmpty = function(obj) { + if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; + for (var key in obj) if (_.has(obj, key)) return false; + return true; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType == 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) == '[object Array]'; + }; + + // Is a given variable an object? + _.isObject = function(obj) { + return obj === Object(obj); + }; + + // Is a given variable an arguments object? + _.isArguments = function(obj) { + return toString.call(obj) == '[object Arguments]'; + }; + if (!_.isArguments(arguments)) { + _.isArguments = function(obj) { + return !!(obj && _.has(obj, 'callee')); + }; + } + + // Is a given value a function? + _.isFunction = function(obj) { + return toString.call(obj) == '[object Function]'; + }; + + // Is a given value a string? + _.isString = function(obj) { + return toString.call(obj) == '[object String]'; + }; + + // Is a given value a number? + _.isNumber = function(obj) { + return toString.call(obj) == '[object Number]'; + }; + + // Is the given value `NaN`? + _.isNaN = function(obj) { + // `NaN` is the only value for which `===` is not reflexive. + return obj !== obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; + }; + + // Is a given value a date? + _.isDate = function(obj) { + return toString.call(obj) == '[object Date]'; + }; + + // Is the given value a regular expression? + _.isRegExp = function(obj) { + return toString.call(obj) == '[object RegExp]'; + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Has own property? + _.has = function(obj, key) { + return hasOwnProperty.call(obj, key); + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iterators. + _.identity = function(value) { + return value; + }; + + // Run a function **n** times. + _.times = function (n, iterator, context) { + for (var i = 0; i < n; i++) iterator.call(context, i); + }; + + // Escape a string for HTML interpolation. + _.escape = function(string) { + return (''+string).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g,'/'); + }; + + // Add your own custom functions to the Underscore object, ensuring that + // they're correctly added to the OOP wrapper as well. + _.mixin = function(obj) { + each(_.functions(obj), function(name){ + addToWrapper(name, _[name] = obj[name]); + }); + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = idCounter++; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /.^/; + + // Within an interpolation, evaluation, or escaping, remove HTML escaping + // that had been previously added. + var unescape = function(code) { + return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'"); + }; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(str, data) { + var c = _.templateSettings; + var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + + 'with(obj||{}){__p.push(\'' + + str.replace(/\\/g, '\\\\') + .replace(/'/g, "\\'") + .replace(c.escape || noMatch, function(match, code) { + return "',_.escape(" + unescape(code) + "),'"; + }) + .replace(c.interpolate || noMatch, function(match, code) { + return "'," + unescape(code) + ",'"; + }) + .replace(c.evaluate || noMatch, function(match, code) { + return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('"; + }) + .replace(/\r/g, '\\r') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + + "');}return __p.join('');"; + var func = new Function('obj', '_', tmpl); + if (data) return func(data, _); + return function(data) { + return func.call(this, data, _); + }; + }; + + // Add a "chain" function, which will delegate to the wrapper. + _.chain = function(obj) { + return _(obj).chain(); + }; + + // The OOP Wrapper + // --------------- + + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + var wrapper = function(obj) { this._wrapped = obj; }; + + // Expose `wrapper.prototype` as `_.prototype` + _.prototype = wrapper.prototype; + + // Helper function to continue chaining intermediate results. + var result = function(obj, chain) { + return chain ? _(obj).chain() : obj; + }; + + // A method to easily add functions to the OOP wrapper. + var addToWrapper = function(name, func) { + wrapper.prototype[name] = function() { + var args = slice.call(arguments); + unshift.call(args, this._wrapped); + return result(func.apply(_, args), this._chain); + }; + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + wrapper.prototype[name] = function() { + var wrapped = this._wrapped; + method.apply(wrapped, arguments); + var length = wrapped.length; + if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0]; + return result(wrapped, this._chain); + }; + }); + + // Add all accessor Array functions to the wrapper. + each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + wrapper.prototype[name] = function() { + return result(method.apply(this._wrapped, arguments), this._chain); + }; + }); + + // Start chaining a wrapped Underscore object. + wrapper.prototype.chain = function() { + this._chain = true; + return this; + }; + + // Extracts the result from a wrapped and chained object. + wrapper.prototype.value = function() { + return this._wrapped; + }; + +}).call(this); diff --git a/for_developers/SphinxDoc/_build/html/_static/underscore.js b/for_developers/SphinxDoc/_build/html/_static/underscore.js new file mode 100644 index 0000000..5b55f32 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_static/underscore.js @@ -0,0 +1,31 @@ +// Underscore.js 1.3.1 +// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore +(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source== +c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c, +h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each= +b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===n)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===n)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(x&&a.map===x)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a== +null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect= +function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e= +e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck= +function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})}); +return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){f==0?b[0]=a:(d=Math.floor(Math.random()*(f+1)),b[f]=b[d],b[d]=a)});return b};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a, +c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest= +b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},[]); +return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c, +d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(p&&a.indexOf===p)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(D&&a.lastIndexOf===D)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g}; +var F=function(){};b.bind=function(a,c){var d,e;if(a.bind===s&&s)return s.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));F.prototype=a.prototype;var b=new F,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a, +c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true: +a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}}; +b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments, +1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)}; +b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"}; +b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a), +function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+ +u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]= +function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain= +true;return this};m.prototype.value=function(){return this._wrapped}}).call(this); diff --git a/for_developers/SphinxDoc/_build/html/_static/up-pressed.png b/for_developers/SphinxDoc/_build/html/_static/up-pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..acee3b68efbbfb9de3bfa73fce2531380f4bd820 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7=6bp~hEy;nOWaX7kgv_n z5uDVZ$q}4%z+FHs{4<xrKmMcI9#?fZj?_2&kmqo|*|bFB16Q6k(|)C}V#$!h_5!`f z^pw?Z?OTxLCc!i{`C$41(FsXRKe+VH>do+TPcX3*&tcosqV<FK$o_^O3<By*g*H?E za%+9(Um_O!*=xn;<c1mS{o<7iveq?xIlwZt;l{L{mNf25+(`z(6Ryl;oOWny{ny4* RH4F?444$rjF6*2UngCoGO}hX9 literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/html/_static/up.png b/for_developers/SphinxDoc/_build/html/_static/up.png new file mode 100644 index 0000000000000000000000000000000000000000..2a940a7da7c14e6a36901e83306849ba7efad4d4 GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4i*LmhONKMUokK+O!9Pb45?sTJ7Md>76*xz z`Kj->uvRIkEbjiSwt{n&#b2u%Y6@1~1?Am&we@pnuJ`Bv_d}Y0!o=guayG~ASSc$0 zno!;8?$B_2ll=juGs~|&zsAAI@j3YQrRwx|Hc##@>Q>0{4J=<>`LO1h{Z=jm&VoXV z!i3|T?9&-G7f5ql^O4e3Un3}SGT2E{#Lw~9qw<hn_c<;fZCPIv${ohQz`)??>gTe~ HDWM4f6G2Yb literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/html/_static/websupport.js b/for_developers/SphinxDoc/_build/html/_static/websupport.js new file mode 100644 index 0000000..79b18e3 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/_static/websupport.js @@ -0,0 +1,808 @@ +/* + * websupport.js + * ~~~~~~~~~~~~~ + * + * sphinx.websupport utilities for all documentation. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +(function($) { + $.fn.autogrow = function() { + return this.each(function() { + var textarea = this; + + $.fn.autogrow.resize(textarea); + + $(textarea) + .focus(function() { + textarea.interval = setInterval(function() { + $.fn.autogrow.resize(textarea); + }, 500); + }) + .blur(function() { + clearInterval(textarea.interval); + }); + }); + }; + + $.fn.autogrow.resize = function(textarea) { + var lineHeight = parseInt($(textarea).css('line-height'), 10); + var lines = textarea.value.split('\n'); + var columns = textarea.cols; + var lineCount = 0; + $.each(lines, function() { + lineCount += Math.ceil(this.length / columns) || 1; + }); + var height = lineHeight * (lineCount + 1); + $(textarea).css('height', height); + }; +})(jQuery); + +(function($) { + var comp, by; + + function init() { + initEvents(); + initComparator(); + } + + function initEvents() { + $(document).on("click", 'a.comment-close', function(event) { + event.preventDefault(); + hide($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.vote', function(event) { + event.preventDefault(); + handleVote($(this)); + }); + $(document).on("click", 'a.reply', function(event) { + event.preventDefault(); + openReply($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.close-reply', function(event) { + event.preventDefault(); + closeReply($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.sort-option', function(event) { + event.preventDefault(); + handleReSort($(this)); + }); + $(document).on("click", 'a.show-proposal', function(event) { + event.preventDefault(); + showProposal($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.hide-proposal', function(event) { + event.preventDefault(); + hideProposal($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.show-propose-change', function(event) { + event.preventDefault(); + showProposeChange($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.hide-propose-change', function(event) { + event.preventDefault(); + hideProposeChange($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.accept-comment', function(event) { + event.preventDefault(); + acceptComment($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.delete-comment', function(event) { + event.preventDefault(); + deleteComment($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.comment-markup', function(event) { + event.preventDefault(); + toggleCommentMarkupBox($(this).attr('id').substring(2)); + }); + } + + /** + * Set comp, which is a comparator function used for sorting and + * inserting comments into the list. + */ + function setComparator() { + // If the first three letters are "asc", sort in ascending order + // and remove the prefix. + if (by.substring(0,3) == 'asc') { + var i = by.substring(3); + comp = function(a, b) { return a[i] - b[i]; }; + } else { + // Otherwise sort in descending order. + comp = function(a, b) { return b[by] - a[by]; }; + } + + // Reset link styles and format the selected sort option. + $('a.sel').attr('href', '#').removeClass('sel'); + $('a.by' + by).removeAttr('href').addClass('sel'); + } + + /** + * Create a comp function. If the user has preferences stored in + * the sortBy cookie, use those, otherwise use the default. + */ + function initComparator() { + by = 'rating'; // Default to sort by rating. + // If the sortBy cookie is set, use that instead. + if (document.cookie.length > 0) { + var start = document.cookie.indexOf('sortBy='); + if (start != -1) { + start = start + 7; + var end = document.cookie.indexOf(";", start); + if (end == -1) { + end = document.cookie.length; + by = unescape(document.cookie.substring(start, end)); + } + } + } + setComparator(); + } + + /** + * Show a comment div. + */ + function show(id) { + $('#ao' + id).hide(); + $('#ah' + id).show(); + var context = $.extend({id: id}, opts); + var popup = $(renderTemplate(popupTemplate, context)).hide(); + popup.find('textarea[name="proposal"]').hide(); + popup.find('a.by' + by).addClass('sel'); + var form = popup.find('#cf' + id); + form.submit(function(event) { + event.preventDefault(); + addComment(form); + }); + $('#s' + id).after(popup); + popup.slideDown('fast', function() { + getComments(id); + }); + } + + /** + * Hide a comment div. + */ + function hide(id) { + $('#ah' + id).hide(); + $('#ao' + id).show(); + var div = $('#sc' + id); + div.slideUp('fast', function() { + div.remove(); + }); + } + + /** + * Perform an ajax request to get comments for a node + * and insert the comments into the comments tree. + */ + function getComments(id) { + $.ajax({ + type: 'GET', + url: opts.getCommentsURL, + data: {node: id}, + success: function(data, textStatus, request) { + var ul = $('#cl' + id); + var speed = 100; + $('#cf' + id) + .find('textarea[name="proposal"]') + .data('source', data.source); + + if (data.comments.length === 0) { + ul.html('<li>No comments yet.</li>'); + ul.data('empty', true); + } else { + // If there are comments, sort them and put them in the list. + var comments = sortComments(data.comments); + speed = data.comments.length * 100; + appendComments(comments, ul); + ul.data('empty', false); + } + $('#cn' + id).slideUp(speed + 200); + ul.slideDown(speed); + }, + error: function(request, textStatus, error) { + showError('Oops, there was a problem retrieving the comments.'); + }, + dataType: 'json' + }); + } + + /** + * Add a comment via ajax and insert the comment into the comment tree. + */ + function addComment(form) { + var node_id = form.find('input[name="node"]').val(); + var parent_id = form.find('input[name="parent"]').val(); + var text = form.find('textarea[name="comment"]').val(); + var proposal = form.find('textarea[name="proposal"]').val(); + + if (text == '') { + showError('Please enter a comment.'); + return; + } + + // Disable the form that is being submitted. + form.find('textarea,input').attr('disabled', 'disabled'); + + // Send the comment to the server. + $.ajax({ + type: "POST", + url: opts.addCommentURL, + dataType: 'json', + data: { + node: node_id, + parent: parent_id, + text: text, + proposal: proposal + }, + success: function(data, textStatus, error) { + // Reset the form. + if (node_id) { + hideProposeChange(node_id); + } + form.find('textarea') + .val('') + .add(form.find('input')) + .removeAttr('disabled'); + var ul = $('#cl' + (node_id || parent_id)); + if (ul.data('empty')) { + $(ul).empty(); + ul.data('empty', false); + } + insertComment(data.comment); + var ao = $('#ao' + node_id); + ao.find('img').attr({'src': opts.commentBrightImage}); + if (node_id) { + // if this was a "root" comment, remove the commenting box + // (the user can get it back by reopening the comment popup) + $('#ca' + node_id).slideUp(); + } + }, + error: function(request, textStatus, error) { + form.find('textarea,input').removeAttr('disabled'); + showError('Oops, there was a problem adding the comment.'); + } + }); + } + + /** + * Recursively append comments to the main comment list and children + * lists, creating the comment tree. + */ + function appendComments(comments, ul) { + $.each(comments, function() { + var div = createCommentDiv(this); + ul.append($(document.createElement('li')).html(div)); + appendComments(this.children, div.find('ul.comment-children')); + // To avoid stagnating data, don't store the comments children in data. + this.children = null; + div.data('comment', this); + }); + } + + /** + * After adding a new comment, it must be inserted in the correct + * location in the comment tree. + */ + function insertComment(comment) { + var div = createCommentDiv(comment); + + // To avoid stagnating data, don't store the comments children in data. + comment.children = null; + div.data('comment', comment); + + var ul = $('#cl' + (comment.node || comment.parent)); + var siblings = getChildren(ul); + + var li = $(document.createElement('li')); + li.hide(); + + // Determine where in the parents children list to insert this comment. + for(i=0; i < siblings.length; i++) { + if (comp(comment, siblings[i]) <= 0) { + $('#cd' + siblings[i].id) + .parent() + .before(li.html(div)); + li.slideDown('fast'); + return; + } + } + + // If we get here, this comment rates lower than all the others, + // or it is the only comment in the list. + ul.append(li.html(div)); + li.slideDown('fast'); + } + + function acceptComment(id) { + $.ajax({ + type: 'POST', + url: opts.acceptCommentURL, + data: {id: id}, + success: function(data, textStatus, request) { + $('#cm' + id).fadeOut('fast'); + $('#cd' + id).removeClass('moderate'); + }, + error: function(request, textStatus, error) { + showError('Oops, there was a problem accepting the comment.'); + } + }); + } + + function deleteComment(id) { + $.ajax({ + type: 'POST', + url: opts.deleteCommentURL, + data: {id: id}, + success: function(data, textStatus, request) { + var div = $('#cd' + id); + if (data == 'delete') { + // Moderator mode: remove the comment and all children immediately + div.slideUp('fast', function() { + div.remove(); + }); + return; + } + // User mode: only mark the comment as deleted + div + .find('span.user-id:first') + .text('[deleted]').end() + .find('div.comment-text:first') + .text('[deleted]').end() + .find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id + + ', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id) + .remove(); + var comment = div.data('comment'); + comment.username = '[deleted]'; + comment.text = '[deleted]'; + div.data('comment', comment); + }, + error: function(request, textStatus, error) { + showError('Oops, there was a problem deleting the comment.'); + } + }); + } + + function showProposal(id) { + $('#sp' + id).hide(); + $('#hp' + id).show(); + $('#pr' + id).slideDown('fast'); + } + + function hideProposal(id) { + $('#hp' + id).hide(); + $('#sp' + id).show(); + $('#pr' + id).slideUp('fast'); + } + + function showProposeChange(id) { + $('#pc' + id).hide(); + $('#hc' + id).show(); + var textarea = $('#pt' + id); + textarea.val(textarea.data('source')); + $.fn.autogrow.resize(textarea[0]); + textarea.slideDown('fast'); + } + + function hideProposeChange(id) { + $('#hc' + id).hide(); + $('#pc' + id).show(); + var textarea = $('#pt' + id); + textarea.val('').removeAttr('disabled'); + textarea.slideUp('fast'); + } + + function toggleCommentMarkupBox(id) { + $('#mb' + id).toggle(); + } + + /** Handle when the user clicks on a sort by link. */ + function handleReSort(link) { + var classes = link.attr('class').split(/\s+/); + for (var i=0; i<classes.length; i++) { + if (classes[i] != 'sort-option') { + by = classes[i].substring(2); + } + } + setComparator(); + // Save/update the sortBy cookie. + var expiration = new Date(); + expiration.setDate(expiration.getDate() + 365); + document.cookie= 'sortBy=' + escape(by) + + ';expires=' + expiration.toUTCString(); + $('ul.comment-ul').each(function(index, ul) { + var comments = getChildren($(ul), true); + comments = sortComments(comments); + appendComments(comments, $(ul).empty()); + }); + } + + /** + * Function to process a vote when a user clicks an arrow. + */ + function handleVote(link) { + if (!opts.voting) { + showError("You'll need to login to vote."); + return; + } + + var id = link.attr('id'); + if (!id) { + // Didn't click on one of the voting arrows. + return; + } + // If it is an unvote, the new vote value is 0, + // Otherwise it's 1 for an upvote, or -1 for a downvote. + var value = 0; + if (id.charAt(1) != 'u') { + value = id.charAt(0) == 'u' ? 1 : -1; + } + // The data to be sent to the server. + var d = { + comment_id: id.substring(2), + value: value + }; + + // Swap the vote and unvote links. + link.hide(); + $('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id) + .show(); + + // The div the comment is displayed in. + var div = $('div#cd' + d.comment_id); + var data = div.data('comment'); + + // If this is not an unvote, and the other vote arrow has + // already been pressed, unpress it. + if ((d.value !== 0) && (data.vote === d.value * -1)) { + $('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide(); + $('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show(); + } + + // Update the comments rating in the local data. + data.rating += (data.vote === 0) ? d.value : (d.value - data.vote); + data.vote = d.value; + div.data('comment', data); + + // Change the rating text. + div.find('.rating:first') + .text(data.rating + ' point' + (data.rating == 1 ? '' : 's')); + + // Send the vote information to the server. + $.ajax({ + type: "POST", + url: opts.processVoteURL, + data: d, + error: function(request, textStatus, error) { + showError('Oops, there was a problem casting that vote.'); + } + }); + } + + /** + * Open a reply form used to reply to an existing comment. + */ + function openReply(id) { + // Swap out the reply link for the hide link + $('#rl' + id).hide(); + $('#cr' + id).show(); + + // Add the reply li to the children ul. + var div = $(renderTemplate(replyTemplate, {id: id})).hide(); + $('#cl' + id) + .prepend(div) + // Setup the submit handler for the reply form. + .find('#rf' + id) + .submit(function(event) { + event.preventDefault(); + addComment($('#rf' + id)); + closeReply(id); + }) + .find('input[type=button]') + .click(function() { + closeReply(id); + }); + div.slideDown('fast', function() { + $('#rf' + id).find('textarea').focus(); + }); + } + + /** + * Close the reply form opened with openReply. + */ + function closeReply(id) { + // Remove the reply div from the DOM. + $('#rd' + id).slideUp('fast', function() { + $(this).remove(); + }); + + // Swap out the hide link for the reply link + $('#cr' + id).hide(); + $('#rl' + id).show(); + } + + /** + * Recursively sort a tree of comments using the comp comparator. + */ + function sortComments(comments) { + comments.sort(comp); + $.each(comments, function() { + this.children = sortComments(this.children); + }); + return comments; + } + + /** + * Get the children comments from a ul. If recursive is true, + * recursively include childrens' children. + */ + function getChildren(ul, recursive) { + var children = []; + ul.children().children("[id^='cd']") + .each(function() { + var comment = $(this).data('comment'); + if (recursive) + comment.children = getChildren($(this).find('#cl' + comment.id), true); + children.push(comment); + }); + return children; + } + + /** Create a div to display a comment in. */ + function createCommentDiv(comment) { + if (!comment.displayed && !opts.moderator) { + return $('<div class="moderate">Thank you! Your comment will show up ' + + 'once it is has been approved by a moderator.</div>'); + } + // Prettify the comment rating. + comment.pretty_rating = comment.rating + ' point' + + (comment.rating == 1 ? '' : 's'); + // Make a class (for displaying not yet moderated comments differently) + comment.css_class = comment.displayed ? '' : ' moderate'; + // Create a div for this comment. + var context = $.extend({}, opts, comment); + var div = $(renderTemplate(commentTemplate, context)); + + // If the user has voted on this comment, highlight the correct arrow. + if (comment.vote) { + var direction = (comment.vote == 1) ? 'u' : 'd'; + div.find('#' + direction + 'v' + comment.id).hide(); + div.find('#' + direction + 'u' + comment.id).show(); + } + + if (opts.moderator || comment.text != '[deleted]') { + div.find('a.reply').show(); + if (comment.proposal_diff) + div.find('#sp' + comment.id).show(); + if (opts.moderator && !comment.displayed) + div.find('#cm' + comment.id).show(); + if (opts.moderator || (opts.username == comment.username)) + div.find('#dc' + comment.id).show(); + } + return div; + } + + /** + * A simple template renderer. Placeholders such as <%id%> are replaced + * by context['id'] with items being escaped. Placeholders such as <#id#> + * are not escaped. + */ + function renderTemplate(template, context) { + var esc = $(document.createElement('div')); + + function handle(ph, escape) { + var cur = context; + $.each(ph.split('.'), function() { + cur = cur[this]; + }); + return escape ? esc.text(cur || "").html() : cur; + } + + return template.replace(/<([%#])([\w\.]*)\1>/g, function() { + return handle(arguments[2], arguments[1] == '%' ? true : false); + }); + } + + /** Flash an error message briefly. */ + function showError(message) { + $(document.createElement('div')).attr({'class': 'popup-error'}) + .append($(document.createElement('div')) + .attr({'class': 'error-message'}).text(message)) + .appendTo('body') + .fadeIn("slow") + .delay(2000) + .fadeOut("slow"); + } + + /** Add a link the user uses to open the comments popup. */ + $.fn.comment = function() { + return this.each(function() { + var id = $(this).attr('id').substring(1); + var count = COMMENT_METADATA[id]; + var title = count + ' comment' + (count == 1 ? '' : 's'); + var image = count > 0 ? opts.commentBrightImage : opts.commentImage; + var addcls = count == 0 ? ' nocomment' : ''; + $(this) + .append( + $(document.createElement('a')).attr({ + href: '#', + 'class': 'sphinx-comment-open' + addcls, + id: 'ao' + id + }) + .append($(document.createElement('img')).attr({ + src: image, + alt: 'comment', + title: title + })) + .click(function(event) { + event.preventDefault(); + show($(this).attr('id').substring(2)); + }) + ) + .append( + $(document.createElement('a')).attr({ + href: '#', + 'class': 'sphinx-comment-close hidden', + id: 'ah' + id + }) + .append($(document.createElement('img')).attr({ + src: opts.closeCommentImage, + alt: 'close', + title: 'close' + })) + .click(function(event) { + event.preventDefault(); + hide($(this).attr('id').substring(2)); + }) + ); + }); + }; + + var opts = { + processVoteURL: '/_process_vote', + addCommentURL: '/_add_comment', + getCommentsURL: '/_get_comments', + acceptCommentURL: '/_accept_comment', + deleteCommentURL: '/_delete_comment', + commentImage: '/static/_static/comment.png', + closeCommentImage: '/static/_static/comment-close.png', + loadingImage: '/static/_static/ajax-loader.gif', + commentBrightImage: '/static/_static/comment-bright.png', + upArrow: '/static/_static/up.png', + downArrow: '/static/_static/down.png', + upArrowPressed: '/static/_static/up-pressed.png', + downArrowPressed: '/static/_static/down-pressed.png', + voting: false, + moderator: false + }; + + if (typeof COMMENT_OPTIONS != "undefined") { + opts = jQuery.extend(opts, COMMENT_OPTIONS); + } + + var popupTemplate = '\ + <div class="sphinx-comments" id="sc<%id%>">\ + <p class="sort-options">\ + Sort by:\ + <a href="#" class="sort-option byrating">best rated</a>\ + <a href="#" class="sort-option byascage">newest</a>\ + <a href="#" class="sort-option byage">oldest</a>\ + </p>\ + <div class="comment-header">Comments</div>\ + <div class="comment-loading" id="cn<%id%>">\ + loading comments... <img src="<%loadingImage%>" alt="" /></div>\ + <ul id="cl<%id%>" class="comment-ul"></ul>\ + <div id="ca<%id%>">\ + <p class="add-a-comment">Add a comment\ + (<a href="#" class="comment-markup" id="ab<%id%>">markup</a>):</p>\ + <div class="comment-markup-box" id="mb<%id%>">\ + reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \ + <code>``code``</code>, \ + code blocks: <code>::</code> and an indented block after blank line</div>\ + <form method="post" id="cf<%id%>" class="comment-form" action="">\ + <textarea name="comment" cols="80"></textarea>\ + <p class="propose-button">\ + <a href="#" id="pc<%id%>" class="show-propose-change">\ + Propose a change ▹\ + </a>\ + <a href="#" id="hc<%id%>" class="hide-propose-change">\ + Propose a change ▿\ + </a>\ + </p>\ + <textarea name="proposal" id="pt<%id%>" cols="80"\ + spellcheck="false"></textarea>\ + <input type="submit" value="Add comment" />\ + <input type="hidden" name="node" value="<%id%>" />\ + <input type="hidden" name="parent" value="" />\ + </form>\ + </div>\ + </div>'; + + var commentTemplate = '\ + <div id="cd<%id%>" class="sphinx-comment<%css_class%>">\ + <div class="vote">\ + <div class="arrow">\ + <a href="#" id="uv<%id%>" class="vote" title="vote up">\ + <img src="<%upArrow%>" />\ + </a>\ + <a href="#" id="uu<%id%>" class="un vote" title="vote up">\ + <img src="<%upArrowPressed%>" />\ + </a>\ + </div>\ + <div class="arrow">\ + <a href="#" id="dv<%id%>" class="vote" title="vote down">\ + <img src="<%downArrow%>" id="da<%id%>" />\ + </a>\ + <a href="#" id="du<%id%>" class="un vote" title="vote down">\ + <img src="<%downArrowPressed%>" />\ + </a>\ + </div>\ + </div>\ + <div class="comment-content">\ + <p class="tagline comment">\ + <span class="user-id"><%username%></span>\ + <span class="rating"><%pretty_rating%></span>\ + <span class="delta"><%time.delta%></span>\ + </p>\ + <div class="comment-text comment"><#text#></div>\ + <p class="comment-opts comment">\ + <a href="#" class="reply hidden" id="rl<%id%>">reply ▹</a>\ + <a href="#" class="close-reply" id="cr<%id%>">reply ▿</a>\ + <a href="#" id="sp<%id%>" class="show-proposal">proposal ▹</a>\ + <a href="#" id="hp<%id%>" class="hide-proposal">proposal ▿</a>\ + <a href="#" id="dc<%id%>" class="delete-comment hidden">delete</a>\ + <span id="cm<%id%>" class="moderation hidden">\ + <a href="#" id="ac<%id%>" class="accept-comment">accept</a>\ + </span>\ + </p>\ + <pre class="proposal" id="pr<%id%>">\ +<#proposal_diff#>\ + </pre>\ + <ul class="comment-children" id="cl<%id%>"></ul>\ + </div>\ + <div class="clearleft"></div>\ + </div>\ + </div>'; + + var replyTemplate = '\ + <li>\ + <div class="reply-div" id="rd<%id%>">\ + <form id="rf<%id%>">\ + <textarea name="comment" cols="80"></textarea>\ + <input type="submit" value="Add reply" />\ + <input type="button" value="Cancel" />\ + <input type="hidden" name="parent" value="<%id%>" />\ + <input type="hidden" name="node" value="" />\ + </form>\ + </div>\ + </li>'; + + $(document).ready(function() { + init(); + }); +})(jQuery); + +$(document).ready(function() { + // add comment anchors for all paragraphs that are commentable + $('.sphinx-has-comment').comment(); + + // highlight search words in search results + $("div.context").each(function() { + var params = $.getQueryParameters(); + var terms = (params.q) ? params.q[0].split(/\s+/) : []; + var result = $(this); + $.each(terms, function() { + result.highlightText(this.toLowerCase(), 'highlighted'); + }); + }); + + // directly open comment window if requested + var anchor = document.location.hash; + if (anchor.substring(0, 9) == '#comment-') { + $('#ao' + anchor.substring(9)).click(); + document.location.hash = '#s' + anchor.substring(9); + } +}); diff --git a/for_developers/SphinxDoc/_build/html/code.html b/for_developers/SphinxDoc/_build/html/code.html new file mode 100644 index 0000000..3890050 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/code.html @@ -0,0 +1,415 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Auto Generated Documentation — flex_extract_test 7.1 documentation</title> + <link rel="stylesheet" href="_static/classic.css" type="text/css" /> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: './', + VERSION: '7.1', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script type="text/javascript" src="_static/jquery.js"></script> + <script type="text/javascript" src="_static/underscore.js"></script> + <script type="text/javascript" src="_static/doctools.js"></script> + <link rel="index" title="Index" href="genindex.html" /> + <link rel="search" title="Search" href="search.html" /> + <link rel="prev" title="Welcome to flex_extract_test’s documentation!" href="index.html" /> + </head> + <body> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="py-modindex.html" title="Python Module Index" + >modules</a> |</li> + <li class="right" > + <a href="index.html" title="Welcome to flex_extract_test’s documentation!" + accesskey="P">previous</a> |</li> + <li class="nav-item nav-item-0"><a href="index.html">flex_extract_test 7.1 documentation</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body" role="main"> + + <div class="section" id="module-Tools"> +<span id="auto-generated-documentation"></span><h1>Auto Generated Documentation<a class="headerlink" href="#module-Tools" title="Permalink to this headline">¶</a></h1> +<dl class="function"> +<dt id="Tools.cleanup"> +<code class="descclassname">Tools.</code><code class="descname">cleanup</code><span class="sig-paren">(</span><em>c</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/Tools.html#cleanup"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#Tools.cleanup" title="Permalink to this definition">¶</a></dt> +<dd><dl class="docutils"> +<dt>@Description:</dt> +<dd>Remove all files from intermediate directory +(inputdir from control file).</dd> +<dt>@Input:</dt> +<dd><dl class="first last docutils"> +<dt>c: instance of class Control</dt> +<dd><p class="first">Contains all the parameters of control files, which are e.g.: +DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, +STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, +LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, +OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, +ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, +MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME +DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS</p> +<p class="last">For more information about format and content of the parameter +see documentation.</p> +</dd> +</dl> +</dd> +<dt>@Return:</dt> +<dd><nothing></dd> +</dl> +</dd></dl> + +<dl class="function"> +<dt id="Tools.getListAsString"> +<code class="descclassname">Tools.</code><code class="descname">getListAsString</code><span class="sig-paren">(</span><em>listobj</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/Tools.html#getListAsString"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#Tools.getListAsString" title="Permalink to this definition">¶</a></dt> +<dd><p>@Description:</p> +</dd></dl> + +<dl class="function"> +<dt id="Tools.init128"> +<code class="descclassname">Tools.</code><code class="descname">init128</code><span class="sig-paren">(</span><em>fn</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/Tools.html#init128"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#Tools.init128" title="Permalink to this definition">¶</a></dt> +<dd><dl class="docutils"> +<dt>@Description:</dt> +<dd>Opens and reads the grib file with table 128 information.</dd> +<dt>@Input:</dt> +<dd><dl class="first last docutils"> +<dt>fn: string</dt> +<dd>Path to file of ECMWF grib table number 128.</dd> +</dl> +</dd> +<dt>@Return:</dt> +<dd><dl class="first last docutils"> +<dt>table128: dictionary</dt> +<dd>Contains the ECMWF grib table 128 information. +The key is the parameter number and the value is the +short name of the parameter.</dd> +</dl> +</dd> +</dl> +</dd></dl> + +<dl class="function"> +<dt id="Tools.interpret_args_and_control"> +<code class="descclassname">Tools.</code><code class="descname">interpret_args_and_control</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/Tools.html#interpret_args_and_control"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#Tools.interpret_args_and_control" title="Permalink to this definition">¶</a></dt> +<dd><dl class="docutils"> +<dt>@Description:</dt> +<dd>Assigns the command line arguments and reads control file +content. Apply default values for non mentioned arguments.</dd> +<dt>@Input:</dt> +<dd><nothing></dd> +<dt>@Return:</dt> +<dd><dl class="first last docutils"> +<dt>args: instance of ArgumentParser</dt> +<dd>Contains the commandline arguments from script/program call.</dd> +<dt>c: instance of class Control</dt> +<dd>Contains all necessary information of a control file. The parameters +are: DAY1, DAY2, DTIME, MAXSTEP, TYPE, TIME, STEP, CLASS, STREAM, +NUMBER, EXPVER, GRID, LEFT, LOWER, UPPER, RIGHT, LEVEL, LEVELIST, +RESOL, GAUSS, ACCURACY, OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, +SMOOTH, FORMAT, ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, +ECFSDIR, MAILOPS, MAILFAIL, GRIB2FLEXPART, DEBUG, INPUTDIR, +OUTPUTDIR, FLEXPART_ROOT_SCRIPTS +For more information about format and content of the parameter see +documentation.</dd> +</dl> +</dd> +</dl> +</dd></dl> + +<dl class="function"> +<dt id="Tools.myerror"> +<code class="descclassname">Tools.</code><code class="descname">myerror</code><span class="sig-paren">(</span><em>c</em>, <em>message='ERROR'</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/Tools.html#myerror"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#Tools.myerror" title="Permalink to this definition">¶</a></dt> +<dd><dl class="docutils"> +<dt>@Description:</dt> +<dd>Prints a specified error message which can be passed to the function +before exiting the program.</dd> +<dt>@Input:</dt> +<dd><dl class="first last docutils"> +<dt>c: instance of class Control</dt> +<dd><p class="first">Contains all the parameters of control files, which are e.g.: +DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, +STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, +LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, +OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, +ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, +MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME +DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS</p> +<p class="last">For more information about format and content of the parameter +see documentation.</p> +</dd> +<dt>message: string, optional</dt> +<dd>Error message. Default value is “ERROR”.</dd> +</dl> +</dd> +<dt>@Return:</dt> +<dd><nothing></dd> +</dl> +</dd></dl> + +<dl class="function"> +<dt id="Tools.normalexit"> +<code class="descclassname">Tools.</code><code class="descname">normalexit</code><span class="sig-paren">(</span><em>c</em>, <em>message='Done!'</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/Tools.html#normalexit"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#Tools.normalexit" title="Permalink to this definition">¶</a></dt> +<dd><dl class="docutils"> +<dt>@Description:</dt> +<dd>Prints a specific exit message which can be passed to the function.</dd> +<dt>@Input:</dt> +<dd><dl class="first last docutils"> +<dt>c: instance of class Control</dt> +<dd><p class="first">Contains all the parameters of control files, which are e.g.: +DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, +STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, +LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, +OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, +ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, +MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME +DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS</p> +<p class="last">For more information about format and content of the parameter +see documentation.</p> +</dd> +<dt>message: string, optional</dt> +<dd>Message for exiting program. Default value is “Done!”.</dd> +</dl> +</dd> +<dt>@Return:</dt> +<dd><nothing></dd> +</dl> +</dd></dl> + +<dl class="function"> +<dt id="Tools.product"> +<code class="descclassname">Tools.</code><code class="descname">product</code><span class="sig-paren">(</span><em>*args</em>, <em>**kwds</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/Tools.html#product"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#Tools.product" title="Permalink to this definition">¶</a></dt> +<dd><dl class="docutils"> +<dt>@Description:</dt> +<dd><p class="first">This method is taken from an example at the ECMWF wiki website. +<a class="reference external" href="https://software.ecmwf.int/wiki/display/GRIB/index.py">https://software.ecmwf.int/wiki/display/GRIB/index.py</a>; 2018-03-16</p> +<p>This method combines the single characters of the passed arguments +with each other. So that each character of each argument value +will be combined with each character of the other arguments as a tuple.</p> +<p class="last">Example: +product(‘ABCD’, ‘xy’) –> Ax Ay Bx By Cx Cy Dx Dy +product(range(2), repeat = 3) –> 000 001 010 011 100 101 110 111</p> +</dd> +<dt>@Input:</dt> +<dd><dl class="first last docutils"> +<dt><a href="#id1"><span class="problematic" id="id2">*</span></a>args: tuple</dt> +<dd>Positional arguments (arbitrary number).</dd> +<dt><a href="#id3"><span class="problematic" id="id4">**</span></a>kwds: dictionary</dt> +<dd>Contains all the keyword arguments from <a href="#id5"><span class="problematic" id="id6">*</span></a>args.</dd> +</dl> +</dd> +<dt>@Return:</dt> +<dd><dl class="first last docutils"> +<dt>prod: tuple</dt> +<dd>Return will be done with “yield”. A tuple of combined arguments. +See example in description above.</dd> +</dl> +</dd> +</dl> +</dd></dl> + +<dl class="function"> +<dt id="Tools.silentremove"> +<code class="descclassname">Tools.</code><code class="descname">silentremove</code><span class="sig-paren">(</span><em>filename</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/Tools.html#silentremove"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#Tools.silentremove" title="Permalink to this definition">¶</a></dt> +<dd><dl class="docutils"> +<dt>@Description:</dt> +<dd>Removes the file which name is passed to the function if +it exists. The function does not fail if the file does not +exist.</dd> +<dt>@Input:</dt> +<dd><dl class="first last docutils"> +<dt>filename: string</dt> +<dd>The name of the file to be removed without notification.</dd> +</dl> +</dd> +<dt>@Return:</dt> +<dd><nothing></dd> +</dl> +</dd></dl> + +<dl class="function"> +<dt id="Tools.toparamId"> +<code class="descclassname">Tools.</code><code class="descname">toparamId</code><span class="sig-paren">(</span><em>pars</em>, <em>table</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/Tools.html#toparamId"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#Tools.toparamId" title="Permalink to this definition">¶</a></dt> +<dd><dl class="docutils"> +<dt>@Description:</dt> +<dd>Transform parameter names to parameter ids +with ECMWF grib table 128.</dd> +<dt>@Input:</dt> +<dd><dl class="first last docutils"> +<dt>pars: string</dt> +<dd>Addpar argument from control file in the format of +parameter names instead of ids. The parameter short +names are sepearted with “/” and they are passed as +one single string.</dd> +<dt>table: dictionary</dt> +<dd>Contains the ECMWF grib table 128 information. +The key is the parameter number and the value is the +short name of the parameter.</dd> +</dl> +</dd> +<dt>@Return:</dt> +<dd><dl class="first last docutils"> +<dt>ipar: list of integer</dt> +<dd>List of addpar parameters from control file transformed to +parameter ids in the format of integer.</dd> +</dl> +</dd> +</dl> +</dd></dl> + +<dl class="class"> +<dt id="Tools.Control"> +<em class="property">class </em><code class="descclassname">Tools.</code><code class="descname">Control</code><a class="headerlink" href="#Tools.Control" title="Permalink to this definition">¶</a></dt> +<dd><p>@Author: Leopold Haimberger (University of Vienna)</p> +<p>@Date: November 2015</p> +<dl class="docutils"> +<dt>@ChangeHistory:</dt> +<dd><dl class="first last docutils"> +<dt>February 2018 - Anne Philipp (University of Vienna):</dt> +<dd><ul class="first last simple"> +<li>applied PEP8 style guide</li> +<li>added documentation</li> +<li>applied some minor modifications in programming style/structure</li> +<li>moved Control class in a file for its own</li> +</ul> +</dd> +</dl> +</dd> +<dt>@License:</dt> +<dd><ol class="first upperalpha simple" start="3"> +<li>Copyright 2015-2018.</li> +</ol> +<p class="last">This software is licensed under the terms of the Apache Licence Version 2.0 +which can be obtained at <a class="reference external" href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>.</p> +</dd> +<dt>@Requirements:</dt> +<dd>A standard python 2.6 or 2.7 installation</dd> +<dt>@Description:</dt> +<dd>The Control files are the steering part of the FLEXPART extraction +software. All necessary parameters needed to retrieve the data fields +from the MARS archive for driving FLEXPART are set in a Control file. +Some specific parameters like the start and end dates can be overwritten +by the command line parameters, but in generel all parameters needed +for a complete set of fields for FLEXPART can be set in the Control files.</dd> +</dl> +<dl class="class"> +<dt id="Tools.Control.Control"> +<em class="property">class </em><code class="descname">Control</code><span class="sig-paren">(</span><em>filename</em><span class="sig-paren">)</span><a class="headerlink" href="#Tools.Control.Control" title="Permalink to this definition">¶</a></dt> +<dd><p>Class containing the information of the ECMWFDATA control file.</p> +<p>Contains all the parameters of control files, which are e.g.: +DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, +STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, +LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, +OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, +ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, +MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, +BASETIME, DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS</p> +<p>For more information about format and content of the parameter +see documentation.</p> +<dl class="method"> +<dt id="Tools.Control.Control.tolist"> +<code class="descname">tolist</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#Tools.Control.Control.tolist" title="Permalink to this definition">¶</a></dt> +<dd><dl class="docutils"> +<dt>@Description:</dt> +<dd>Just generates a list of strings containing the attributes and +assigned values except the attributes “_expanded”, “exedir”, +“ecmwfdatadir” and “flexpart_root_scripts”.</dd> +<dt>@Input:</dt> +<dd><dl class="first last docutils"> +<dt>self: instance of Control class</dt> +<dd>Description see class documentation.</dd> +</dl> +</dd> +<dt>@Return:</dt> +<dd><dl class="first last docutils"> +<dt>l: list</dt> +<dd>A sorted list of the all Control class attributes with +their values except the attributes “_expanded”, “exedir”, +“ecmwfdatadir” and “flexpart_root_scripts”.</dd> +</dl> +</dd> +</dl> +</dd></dl> + +</dd></dl> + +<dl class="attribute"> +<dt id="Tools.Control.Tools"> +<code class="descname">Tools</code><em class="property"> = <module 'Tools' from '/nas16/tmc/Anne/Interpolation/flexextract/flexextract/python/Tools.pyc'></em><a class="headerlink" href="#Tools.Control.Tools" title="Permalink to this definition">¶</a></dt> +<dd></dd></dl> + +<dl class="attribute"> +<dt id="Tools.Control.inspect"> +<code class="descname">inspect</code><em class="property"> = <module 'inspect' from '/opt/anaconda/lib/python2.7/inspect.pyc'></em><a class="headerlink" href="#Tools.Control.inspect" title="Permalink to this definition">¶</a></dt> +<dd></dd></dl> + +<dl class="attribute"> +<dt id="Tools.Control.os"> +<code class="descname">os</code><em class="property"> = <module 'os' from '/opt/anaconda/lib/python2.7/os.pyc'></em><a class="headerlink" href="#Tools.Control.os" title="Permalink to this definition">¶</a></dt> +<dd></dd></dl> + +</dd></dl> + +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar" role="navigation" aria-label="main navigation"> + <div class="sphinxsidebarwrapper"> + <h4>Previous topic</h4> + <p class="topless"><a href="index.html" + title="previous chapter">Welcome to flex_extract_test’s documentation!</a></p> +<div id="searchbox" style="display: none" role="search"> + <h3>Quick search</h3> + <form class="search" action="search.html" method="get"> + <div><input type="text" name="q" /></div> + <div><input type="submit" value="Go" /></div> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="genindex.html" title="General Index" + >index</a></li> + <li class="right" > + <a href="py-modindex.html" title="Python Module Index" + >modules</a> |</li> + <li class="right" > + <a href="index.html" title="Welcome to flex_extract_test’s documentation!" + >previous</a> |</li> + <li class="nav-item nav-item-0"><a href="index.html">flex_extract_test 7.1 documentation</a> »</li> + </ul> + </div> + <div class="footer" role="contentinfo"> + © Copyright 2018, AP. + Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6. + </div> + </body> +</html> \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/html/genindex.html b/for_developers/SphinxDoc/_build/html/genindex.html new file mode 100644 index 0000000..343de70 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/genindex.html @@ -0,0 +1,194 @@ + + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Index — flex_extract_test 7.1 documentation</title> + <link rel="stylesheet" href="_static/classic.css" type="text/css" /> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: './', + VERSION: '7.1', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script type="text/javascript" src="_static/jquery.js"></script> + <script type="text/javascript" src="_static/underscore.js"></script> + <script type="text/javascript" src="_static/doctools.js"></script> + <link rel="index" title="Index" href="#" /> + <link rel="search" title="Search" href="search.html" /> + </head> + <body> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="#" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="py-modindex.html" title="Python Module Index" + >modules</a> |</li> + <li class="nav-item nav-item-0"><a href="index.html">flex_extract_test 7.1 documentation</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body" role="main"> + + +<h1 id="index">Index</h1> + +<div class="genindex-jumpbox"> + <a href="#C"><strong>C</strong></a> + | <a href="#G"><strong>G</strong></a> + | <a href="#I"><strong>I</strong></a> + | <a href="#M"><strong>M</strong></a> + | <a href="#N"><strong>N</strong></a> + | <a href="#O"><strong>O</strong></a> + | <a href="#P"><strong>P</strong></a> + | <a href="#S"><strong>S</strong></a> + | <a href="#T"><strong>T</strong></a> + +</div> +<h2 id="C">C</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="code.html#Tools.cleanup">cleanup() (in module Tools)</a> +</li> + </ul></td> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="code.html#Tools.Control">Control (class in Tools)</a> +</li> + <li><a href="code.html#Tools.Control.Control">Control.Control (class in Tools)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="G">G</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="code.html#Tools.getListAsString">getListAsString() (in module Tools)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="I">I</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="code.html#Tools.init128">init128() (in module Tools)</a> +</li> + </ul></td> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="code.html#Tools.Control.inspect">inspect (Tools.Control attribute)</a> +</li> + <li><a href="code.html#Tools.interpret_args_and_control">interpret_args_and_control() (in module Tools)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="M">M</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="code.html#Tools.myerror">myerror() (in module Tools)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="N">N</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="code.html#Tools.normalexit">normalexit() (in module Tools)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="O">O</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="code.html#Tools.Control.os">os (Tools.Control attribute)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="P">P</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="code.html#Tools.product">product() (in module Tools)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="S">S</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="code.html#Tools.silentremove">silentremove() (in module Tools)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="T">T</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="code.html#Tools.Control.Control.tolist">tolist() (Tools.Control.Control method)</a> +</li> + <li><a href="code.html#module-Tools">Tools (module)</a> + + <ul> + <li><a href="code.html#Tools.Control.Tools">(Tools.Control attribute)</a> +</li> + </ul></li> + </ul></td> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="code.html#Tools.toparamId">toparamId() (in module Tools)</a> +</li> + </ul></td> +</tr></table> + + + + </div> + </div> + </div> + <div class="sphinxsidebar" role="navigation" aria-label="main navigation"> + <div class="sphinxsidebarwrapper"> +<div id="searchbox" style="display: none" role="search"> + <h3>Quick search</h3> + <form class="search" action="search.html" method="get"> + <div><input type="text" name="q" /></div> + <div><input type="submit" value="Go" /></div> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="#" title="General Index" + >index</a></li> + <li class="right" > + <a href="py-modindex.html" title="Python Module Index" + >modules</a> |</li> + <li class="nav-item nav-item-0"><a href="index.html">flex_extract_test 7.1 documentation</a> »</li> + </ul> + </div> + <div class="footer" role="contentinfo"> + © Copyright 2018, AP. + Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6. + </div> + </body> +</html> \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/html/index.html b/for_developers/SphinxDoc/_build/html/index.html new file mode 100644 index 0000000..37003ef --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/index.html @@ -0,0 +1,111 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Welcome to flex_extract_test’s documentation! — flex_extract_test 7.1 documentation</title> + <link rel="stylesheet" href="_static/classic.css" type="text/css" /> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: './', + VERSION: '7.1', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script type="text/javascript" src="_static/jquery.js"></script> + <script type="text/javascript" src="_static/underscore.js"></script> + <script type="text/javascript" src="_static/doctools.js"></script> + <link rel="index" title="Index" href="genindex.html" /> + <link rel="search" title="Search" href="search.html" /> + <link rel="next" title="Auto Generated Documentation" href="code.html" /> + </head> + <body> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="py-modindex.html" title="Python Module Index" + >modules</a> |</li> + <li class="right" > + <a href="code.html" title="Auto Generated Documentation" + accesskey="N">next</a> |</li> + <li class="nav-item nav-item-0"><a href="#">flex_extract_test 7.1 documentation</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body" role="main"> + + <div class="section" id="welcome-to-flex-extract-test-s-documentation"> +<h1>Welcome to flex_extract_test’s documentation!<a class="headerlink" href="#welcome-to-flex-extract-test-s-documentation" title="Permalink to this headline">¶</a></h1> +<div class="toctree-wrapper compound"> +<p class="caption"><span class="caption-text">Contents:</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="code.html">Auto Generated Documentation</a></li> +</ul> +</div> +</div> +<div class="section" id="indices-and-tables"> +<h1>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline">¶</a></h1> +<ul class="simple"> +<li><a class="reference internal" href="genindex.html"><span class="std std-ref">Index</span></a></li> +<li><a class="reference internal" href="py-modindex.html"><span class="std std-ref">Module Index</span></a></li> +<li><a class="reference internal" href="search.html"><span class="std std-ref">Search Page</span></a></li> +</ul> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar" role="navigation" aria-label="main navigation"> + <div class="sphinxsidebarwrapper"> + <h4>Next topic</h4> + <p class="topless"><a href="code.html" + title="next chapter">Auto Generated Documentation</a></p> +<div id="searchbox" style="display: none" role="search"> + <h3>Quick search</h3> + <form class="search" action="search.html" method="get"> + <div><input type="text" name="q" /></div> + <div><input type="submit" value="Go" /></div> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="genindex.html" title="General Index" + >index</a></li> + <li class="right" > + <a href="py-modindex.html" title="Python Module Index" + >modules</a> |</li> + <li class="right" > + <a href="code.html" title="Auto Generated Documentation" + >next</a> |</li> + <li class="nav-item nav-item-0"><a href="#">flex_extract_test 7.1 documentation</a> »</li> + </ul> + </div> + <div class="footer" role="contentinfo"> + © Copyright 2018, AP. + Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6. + </div> + </body> +</html> \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/html/objects.inv b/for_developers/SphinxDoc/_build/html/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..d9bc47a1e4e8a7b4028d4d0a6248afe85db34902 GIT binary patch literal 456 zcmY#Z2rkIT%&Sny%qvUHE6FdaR47X=D$dN$Q!wIERtPA{&q_@$u~JCONv()attcr< zOfHEpNi8nnQdS6qD6~>A*E8f&RtU*RRVYf$P0Y+oNi9;yPg5w#$ShV!%gjkt$ShV! z&d)6<N-Zu<O;IQ<&df_!sLIJq(&MVQHFxq^FJ?o5<L`fq2=2|>IB&`JMGCB}3t9V5 zo6LO2Hp#~$ZRy^hQv2rlCvDqUa<tzq|KyqX_Wx(rtm*I(sWacaq^kK*kVlZk%Nw&k z%dFCOiCxQ<Q{>#oJd<%cTaw6S!N07()$J0EtUm2if6{k_^X4l9Mg#V}?<D;>wsgy> z{&#h9WxJ%X;~xKuW#yAhcgmj-`)PO9qW^Tr#jUJdZ%zEyuj}?W_JFyFd0{WF#nls! zUFQhgmThxb*ia&(BXK87uc6k%-*ei8Kxv<|i<YMA9GGdtvVr@nw)GpA6w_c8SKCuv zmFHF7T}WhbQ_b`IX7=-Nz_P51nac}yPnU{VEP13oLvMq`w5x)@3nT>nGgKl)PG(F# zxB8$i`-D3NZgtg_y-vNp=U07sy|3`=?q3s5q{@G)Kl@Km@x;5$O2>`%ocZaVv9XHX IJSTBC09TvHUH||9 literal 0 HcmV?d00001 diff --git a/for_developers/SphinxDoc/_build/html/py-modindex.html b/for_developers/SphinxDoc/_build/html/py-modindex.html new file mode 100644 index 0000000..fbea89b --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/py-modindex.html @@ -0,0 +1,108 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Python Module Index — flex_extract_test 7.1 documentation</title> + <link rel="stylesheet" href="_static/classic.css" type="text/css" /> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: './', + VERSION: '7.1', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script type="text/javascript" src="_static/jquery.js"></script> + <script type="text/javascript" src="_static/underscore.js"></script> + <script type="text/javascript" src="_static/doctools.js"></script> + <link rel="index" title="Index" href="genindex.html" /> + <link rel="search" title="Search" href="search.html" /> + + + <script type="text/javascript"> + DOCUMENTATION_OPTIONS.COLLAPSE_INDEX = true; + </script> + + + </head> + <body> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="#" title="Python Module Index" + >modules</a> |</li> + <li class="nav-item nav-item-0"><a href="index.html">flex_extract_test 7.1 documentation</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body" role="main"> + + + <h1>Python Module Index</h1> + + <div class="modindex-jumpbox"> + <a href="#cap-t"><strong>t</strong></a> + </div> + + <table class="indextable modindextable"> + <tr class="pcap"><td></td><td> </td><td></td></tr> + <tr class="cap" id="cap-t"><td></td><td> + <strong>t</strong></td><td></td></tr> + <tr> + <td></td> + <td> + <a href="code.html#module-Tools"><code class="xref">Tools</code></a></td><td> + <em></em></td></tr> + </table> + + + </div> + </div> + </div> + <div class="sphinxsidebar" role="navigation" aria-label="main navigation"> + <div class="sphinxsidebarwrapper"> +<div id="searchbox" style="display: none" role="search"> + <h3>Quick search</h3> + <form class="search" action="search.html" method="get"> + <div><input type="text" name="q" /></div> + <div><input type="submit" value="Go" /></div> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="genindex.html" title="General Index" + >index</a></li> + <li class="right" > + <a href="#" title="Python Module Index" + >modules</a> |</li> + <li class="nav-item nav-item-0"><a href="index.html">flex_extract_test 7.1 documentation</a> »</li> + </ul> + </div> + <div class="footer" role="contentinfo"> + © Copyright 2018, AP. + Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6. + </div> + </body> +</html> \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/html/search.html b/for_developers/SphinxDoc/_build/html/search.html new file mode 100644 index 0000000..fa40466 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/search.html @@ -0,0 +1,104 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Search — flex_extract_test 7.1 documentation</title> + <link rel="stylesheet" href="_static/classic.css" type="text/css" /> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: './', + VERSION: '7.1', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script type="text/javascript" src="_static/jquery.js"></script> + <script type="text/javascript" src="_static/underscore.js"></script> + <script type="text/javascript" src="_static/doctools.js"></script> + <script type="text/javascript" src="_static/searchtools.js"></script> + <link rel="index" title="Index" href="genindex.html" /> + <link rel="search" title="Search" href="#" /> + <script type="text/javascript"> + jQuery(function() { Search.loadIndex("searchindex.js"); }); + </script> + + <script type="text/javascript" id="searchindexloader"></script> + + + </head> + <body> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="py-modindex.html" title="Python Module Index" + >modules</a> |</li> + <li class="nav-item nav-item-0"><a href="index.html">flex_extract_test 7.1 documentation</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body" role="main"> + + <h1 id="search-documentation">Search</h1> + <div id="fallback" class="admonition warning"> + <script type="text/javascript">$('#fallback').hide();</script> + <p> + Please activate JavaScript to enable the search + functionality. + </p> + </div> + <p> + From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. + </p> + <form action="" method="get"> + <input type="text" name="q" value="" /> + <input type="submit" value="search" /> + <span id="search-progress" style="padding-left: 10px"></span> + </form> + + <div id="search-results"> + + </div> + + </div> + </div> + </div> + <div class="sphinxsidebar" role="navigation" aria-label="main navigation"> + <div class="sphinxsidebarwrapper"> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="related" role="navigation" aria-label="related navigation"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="genindex.html" title="General Index" + >index</a></li> + <li class="right" > + <a href="py-modindex.html" title="Python Module Index" + >modules</a> |</li> + <li class="nav-item nav-item-0"><a href="index.html">flex_extract_test 7.1 documentation</a> »</li> + </ul> + </div> + <div class="footer" role="contentinfo"> + © Copyright 2018, AP. + Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6. + </div> + </body> +</html> \ No newline at end of file diff --git a/for_developers/SphinxDoc/_build/html/searchindex.js b/for_developers/SphinxDoc/_build/html/searchindex.js new file mode 100644 index 0000000..bc64db1 --- /dev/null +++ b/for_developers/SphinxDoc/_build/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["code","index"],envversion:52,filenames:["code.rst","index.rst"],objects:{"":{Tools:[0,0,0,"-"]},"Tools.Control":{Control:[0,1,1,""],Tools:[0,3,1,""],inspect:[0,3,1,""],os:[0,3,1,""]},"Tools.Control.Control":{tolist:[0,2,1,""]},Tools:{Control:[0,1,1,""],cleanup:[0,4,1,""],getListAsString:[0,4,1,""],init128:[0,4,1,""],interpret_args_and_control:[0,4,1,""],myerror:[0,4,1,""],normalexit:[0,4,1,""],product:[0,4,1,""],silentremove:[0,4,1,""],toparamId:[0,4,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","attribute","Python attribute"],"4":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute","4":"py:function"},terms:{"class":0,"default":0,"function":0,"int":0,"return":0,"short":0,For:0,The:0,_expand:0,abcd:0,about:0,abov:0,accuraci:0,added:0,addpar:0,all:0,anaconda:0,ann:0,apach:0,appli:0,arbitrari:0,archiv:0,arg:0,argument:0,argumentpars:0,assign:0,attribut:0,author:0,auto:1,basetim:0,befor:0,call:0,can:0,changehistori:0,charact:0,cleanup:0,combin:0,command:0,commandlin:0,complet:0,contain:0,content:[0,1],control:0,copyright:0,cwc:0,data:0,date:0,date_chunk:0,day1:0,day2:0,debug:0,descript:0,dictionari:0,directori:0,displai:0,doe:0,done:0,dpdeta:0,drive:0,dtime:0,each:0,ecfsdir:0,ecmwf:0,ecmwfdata:0,ecmwfdatadir:0,ecstorag:0,ectran:0,end:0,end_dat:0,error:0,eta:0,etadiff:0,exampl:0,except:0,exedir:0,exist:0,exit:0,expver:0,extract:0,fail:0,februari:0,field:0,file:0,filenam:0,flexextract:0,flexpart:0,flexpart_root_script:0,flexpartdir:0,format:0,from:0,gauss:0,gener:1,generel:0,getlistasstr:0,grib2flexpart:0,grib:0,grid:0,guid:0,haimberg:0,http:0,ids:0,index:[0,1],inform:0,init128:0,input:0,inputdir:0,inspect:0,instal:0,instanc:0,instead:0,integ:0,intermedi:0,interpol:0,interpret_args_and_control:0,ipar:0,its:0,just:0,kei:0,keyword:0,kwd:0,left:0,leopold:0,level:0,levelist:0,lib:0,licenc:0,licens:0,like:0,line:0,list:0,listobj:0,lower:0,mailfail:0,mailop:0,mar:0,marsclass:0,maxstep:0,mention:0,messag:0,method:0,minor:0,modif:0,modul:[0,1],more:0,move:0,myerror:0,name:0,nas16:0,necessari:0,need:0,non:0,normalexit:0,noth:0,notif:0,novemb:0,number:0,obtain:0,omega:0,omegadiff:0,one:0,open:0,opt:0,option:0,org:0,other:0,outputdir:0,overwritten:0,own:0,page:1,par:0,paramet:0,part:0,pass:0,path:0,pep8:0,philipp:0,posit:0,prefix:0,print:0,prod:0,product:0,program:0,pyc:0,python2:0,python:0,rang:0,read:0,remov:0,repeat:0,requir:0,resol:0,retriev:0,right:0,script:0,search:1,see:0,self:0,sepeart:0,set:0,silentremov:0,singl:0,smooth:0,softwar:0,some:0,sort:0,sourc:0,specif:0,specifi:0,standard:0,start:0,start_dat:0,steer:0,step:0,stream:0,string:0,structur:0,style:0,tabl:0,table128:0,taken:0,term:0,thei:0,thi:0,time:0,tmc:0,tolist:0,tool:0,toparamid:0,transform:0,tupl:0,type:0,under:0,univers:0,upper:0,valu:0,version:0,vienna:0,websit:0,which:0,wiki:0,without:0,wrf:0,www:0,yield:0},titles:["Auto Generated Documentation","Welcome to flex_extract_test\u2019s documentation!"],titleterms:{auto:0,document:[0,1],flex_extract_test:1,gener:0,indic:1,tabl:1,welcom:1}}) \ No newline at end of file diff --git a/for_developers/SphinxDoc/code.rst b/for_developers/SphinxDoc/code.rst new file mode 100644 index 0000000..342bc36 --- /dev/null +++ b/for_developers/SphinxDoc/code.rst @@ -0,0 +1,8 @@ +Auto Generated Documentation +============================ + +.. automodule:: Tools + :members: + +.. autoclass:: Control + :members: diff --git a/for_developers/SphinxDoc/conf.py b/for_developers/SphinxDoc/conf.py new file mode 100644 index 0000000..abc4b4a --- /dev/null +++ b/for_developers/SphinxDoc/conf.py @@ -0,0 +1,170 @@ +# -*- coding: utf-8 -*- +# +# flex_extract_test documentation build configuration file, created by +# sphinx-quickstart on Sun May 6 19:28:54 2018. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# 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('../')) + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx.ext.autodoc', + 'sphinx.ext.coverage', + 'sphinx.ext.viewcode'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'flex_extract_test' +copyright = u'2018, AP' +author = u'AP' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = u'7.1' +# The full version, including alpha/beta/rc tags. +release = u'7.1' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- 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 = 'classic' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# 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'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# This is required for the alabaster theme +# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars +html_sidebars = { + '**': [ + 'relations.html', # needs 'show_related': True theme option to display + 'searchbox.html', + ] +} + + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = 'flex_extract_testdoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'flex_extract_test.tex', u'flex\\_extract\\_test Documentation', + u'AP', 'manual'), +] + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'flex_extract_test', u'flex_extract_test Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'flex_extract_test', u'flex_extract_test Documentation', + author, 'flex_extract_test', 'One line description of project.', + 'Miscellaneous'), +] + + + diff --git a/for_developers/SphinxDoc/index.rst b/for_developers/SphinxDoc/index.rst new file mode 100644 index 0000000..d720b19 --- /dev/null +++ b/for_developers/SphinxDoc/index.rst @@ -0,0 +1,20 @@ +.. flex_extract_test documentation master file, created by + sphinx-quickstart on Sun May 6 19:28:54 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to flex_extract_test's documentation! +============================================= + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + code + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/for_developers/SphinxDoc/make.bat b/for_developers/SphinxDoc/make.bat new file mode 100644 index 0000000..217cd7e --- /dev/null +++ b/for_developers/SphinxDoc/make.bat @@ -0,0 +1,36 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build +set SPHINXPROJ=flex_extract_test + +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% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/for_developers/classes.dot b/for_developers/classes.dot new file mode 100644 index 0000000..8d27fbd --- /dev/null +++ b/for_developers/classes.dot @@ -0,0 +1,9 @@ +digraph "classes" { +charset="utf-8" +rankdir=BT +"0" [label="{ControlFile|accuracy : int\larea : str\lbasetime : NoneType\lcwc : str\ldate_chunk : str\ldebug\ldestination\lec_flexpart_root_scripts : str\lecgid\lecmwfdatadir\lecuid\lend_date : NoneType\lend_step : int\letadiff : str\lexedir\lflexpart_root_scripts : str\lgateway\lgrib2flexpart : str\linputdir : str\lleft\llevel\llevelist\llevels : list\llower\lmakefile : NoneType\lmaxstep : int\lomega : str\lomegadiff : str\loutputdir : str\lparamIds\lprefix : str\lright\lstart_date : NoneType\lstart_step : int\lstep\lupper\l|to_list()\l}", shape="record"]; +"1" [label="{EcFlexpart|accuracy\larea : str\lbasetime\ldates\ldtime\lexpver : str\lgaussian : str\lglevelist\lgrid : str\linputdir : str\llevel\llevelist\lmarsclass\lnumber : str\loutputfilelist : list\lparams : dict\lresol\lserver\lstream\ltypes : dict\l|create()\ldeacc_fluxes()\lprocess_output()\lretrieve()\lwrite_namelist()\l}", shape="record"]; +"2" [label="{GribTools|filenames\l|copy()\lget_keys()\lindex()\lset_keys()\l}", shape="record"]; +"3" [label="{MarsRetrieval|accuracy : str\larea : str\ldate : str\ldtype : str\lexpver : str\lgaussian : str\lgrid : str\llevelist : str\llevtype : str\lmarsclass : str\lnumber : str\lparam : str\lrepres : str\lresol : str\lserver\lstep : str\lstream : str\ltarget : str\ltime : str\l|data_retrieve()\ldisplay_info()\l}", shape="record"]; +"4" [label="{UioFiles|files : list, NoneType\lpattern\l|delete_files()\llist_files()\l}", shape="record"]; +} diff --git a/for_developers/classes.dot.png b/for_developers/classes.dot.png new file mode 100644 index 0000000000000000000000000000000000000000..f0837c367568eabd9e586a72b2f7a183517ff846 GIT binary patch literal 96730 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 literal 0 HcmV?d00001 diff --git a/python/mk_install_tar.sh b/for_developers/mk_install_tar.sh similarity index 100% rename from python/mk_install_tar.sh rename to for_developers/mk_install_tar.sh diff --git a/mk_upload_tarball.sh b/for_developers/mk_upload_tarball.sh similarity index 100% rename from mk_upload_tarball.sh rename to for_developers/mk_upload_tarball.sh diff --git a/for_developers/packages.dot b/for_developers/packages.dot new file mode 100644 index 0000000..1ca9e5c --- /dev/null +++ b/for_developers/packages.dot @@ -0,0 +1,37 @@ +digraph "packages" { +charset="utf-8" +rankdir=BT +"0" [label="ControlFile", shape="box"]; +"1" [label="EcFlexpart", shape="box"]; +"2" [label="GribTools", shape="box"]; +"3" [label="MarsRetrieval", shape="box"]; +"4" [label="UioFiles", shape="box"]; +"5" [label="disaggregation", shape="box"]; +"6" [label="get_mars_data", shape="box"]; +"7" [label="install", shape="box"]; +"8" [label="plot_retrieved", shape="box"]; +"9" [label="prepare_flexpart", shape="box"]; +"10" [label="profiling", shape="box"]; +"11" [label="submit", shape="box"]; +"12" [label="test_suite", shape="box"]; +"13" [label="tools", shape="box"]; +"0" -> "13" [arrowhead="open", arrowtail="none"]; +"1" -> "2" [arrowhead="open", arrowtail="none"]; +"1" -> "3" [arrowhead="open", arrowtail="none"]; +"1" -> "5" [arrowhead="open", arrowtail="none"]; +"1" -> "13" [arrowhead="open", arrowtail="none"]; +"4" -> "13" [arrowhead="open", arrowtail="none"]; +"6" -> "1" [arrowhead="open", arrowtail="none"]; +"6" -> "4" [arrowhead="open", arrowtail="none"]; +"6" -> "13" [arrowhead="open", arrowtail="none"]; +"7" -> "0" [arrowhead="open", arrowtail="none"]; +"8" -> "0" [arrowhead="open", arrowtail="none"]; +"8" -> "4" [arrowhead="open", arrowtail="none"]; +"9" -> "1" [arrowhead="open", arrowtail="none"]; +"9" -> "4" [arrowhead="open", arrowtail="none"]; +"9" -> "13" [arrowhead="open", arrowtail="none"]; +"11" -> "6" [arrowhead="open", arrowtail="none"]; +"11" -> "9" [arrowhead="open", arrowtail="none"]; +"11" -> "13" [arrowhead="open", arrowtail="none"]; +"13" -> "0" [arrowhead="open", arrowtail="none"]; +} diff --git a/for_developers/packages.dot.png b/for_developers/packages.dot.png new file mode 100644 index 0000000000000000000000000000000000000000..080a943aad04ff39604ec6daa48484c6b1cbd0d7 GIT binary patch literal 38473 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 Q{s8QKPgg&ebxsLQ0KI+7Gynhq literal 0 HcmV?d00001 diff --git a/for_developers/pylintrc b/for_developers/pylintrc new file mode 100644 index 0000000..51b4446 --- /dev/null +++ b/for_developers/pylintrc @@ -0,0 +1,552 @@ +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. +jobs=1 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Specify a configuration file. +#rcfile= + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=print-statement, + parameter-unpacking, + unpacking-in-except, + old-raise-syntax, + backtick, + long-suffix, + old-ne-operator, + old-octal-literal, + import-star-module-level, + non-ascii-bytes-literal, + raw-checker-failed, + bad-inline-option, + locally-disabled, + locally-enabled, + file-ignored, + suppressed-message, + useless-suppression, + deprecated-pragma, + apply-builtin, + basestring-builtin, + buffer-builtin, + cmp-builtin, + coerce-builtin, + execfile-builtin, + file-builtin, + long-builtin, + raw_input-builtin, + reduce-builtin, + standarderror-builtin, + unicode-builtin, + xrange-builtin, + coerce-method, + delslice-method, + getslice-method, + setslice-method, + no-absolute-import, + old-division, + dict-iter-method, + dict-view-method, + next-method-called, + metaclass-assignment, + indexing-exception, + raising-string, + reload-builtin, + oct-method, + hex-method, + nonzero-method, + cmp-method, + input-builtin, + round-builtin, + intern-builtin, + unichr-builtin, + map-builtin-not-iterating, + zip-builtin-not-iterating, + range-builtin-not-iterating, + filter-builtin-not-iterating, + using-cmp-argument, + eq-without-hash, + div-method, + idiv-method, + rdiv-method, + exception-message-attribute, + invalid-str-codec, + sys-max-int, + bad-python3-import, + deprecated-string-function, + deprecated-str-translate-call, + deprecated-itertools-function, + deprecated-types-field, + next-method-defined, + dict-items-not-iterating, + dict-keys-not-iterating, + dict-values-not-iterating + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable=c-extension-no-member + + +[REPORTS] + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio).You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages +reports=no + +# Activate the evaluation score. +score=yes + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=optparse.Values,sys.exit + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + + +[SIMILARITIES] + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins + + +[BASIC] + +# Naming style matching correct argument names +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style +#argument-rgx= + +# Naming style matching correct attribute names +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Naming style matching correct class attribute names +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style +#class-attribute-rgx= + +# Naming style matching correct class names +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming-style +#class-rgx= + +# Naming style matching correct constant names +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma +good-names=i, + j, + k, + ex, + Run, + _, + f, + fo, + c, + p, + e, + s, + l, + d, + dd, + v + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# Naming style matching correct inline iteration names +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style +#inlinevar-rgx= + +# Naming style matching correct method names +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style +#method-rgx= + +# Naming style matching correct module names +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +property-classes=abc.abstractproperty + +# Naming style matching correct variable names +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style +#variable-rgx= + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )?<?https?://\S+>?$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=100 + +# Maximum number of lines in a module +max-module-lines=1000 + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma, + dict-separator + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=10 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in a if statement +max-bool-expr=5 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of statements in function / method body +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[IMPORTS] + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub, + TERMIOS, + Bastion, + rexec + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff --git a/python/plot_retrieved.py b/python/plot_retrieved.py deleted file mode 100755 index 45e7bb2..0000000 --- a/python/plot_retrieved.py +++ /dev/null @@ -1,675 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Leopold Haimberger (University of Vienna) -# -# @Date: November 2015 -# -# @Change History: -# -# February 2018 - Anne Philipp (University of Vienna): -# - applied PEP8 style guide -# - added documentation -# - created function main and moved the two function calls for -# arguments and plotting into it -# - added function get_basics to extract the boundary conditions -# of the data fields from the first grib file it gets. -# -# @License: -# (C) Copyright 2015-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Program Functionality: -# Simple tool for creating maps and time series of retrieved fields. -# -# @Program Content: -# - main -# - get_basics -# - get_files_per_date -# - plot_retrieved -# - plot_timeseries -# - plot_map -# - get_plot_args -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import time -import datetime -import os -import inspect -import sys -from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter -import matplotlib -import matplotlib.pyplot as plt -from mpl_toolkits.basemap import Basemap -from eccodes import codes_grib_new_from_file, codes_get, codes_release, \ - codes_get_values -import numpy as np - -# software specific classes and modules from flex_extract -from ControlFile import ControlFile -from UioFiles import UioFiles - -# add path to pythonpath so that python finds its buddies -LOCAL_PYTHON_PATH = os.path.dirname(os.path.abspath( - inspect.getfile(inspect.currentframe()))) -if LOCAL_PYTHON_PATH not in sys.path: - sys.path.append(LOCAL_PYTHON_PATH) - -font = {'family': 'monospace', 'size': 12} -matplotlib.rcParams['xtick.major.pad'] = '20' -matplotlib.rc('font', **font) -# ------------------------------------------------------------------------------ -# FUNCTION -# ------------------------------------------------------------------------------ -def main(): - ''' - @Description: - If plot_retrieved is called from command line, this function controls - the program flow and calls the argumentparser function and - the plot_retrieved function for plotting the retrieved GRIB data. - - @Input: - <nothing> - - @Return: - <nothing> - ''' - args, c = get_plot_args() - plot_retrieved(c) - - return - -def get_basics(ifile, verb=False): - """ - @Description: - An example grib file will be opened and basic information will - be extracted. These information are important for later use and the - initialization of numpy arrays for data storing. - - @Input: - ifile: string - Contains the full absolute path to the ECMWF grib file. - - verb (opt): bool - Is True if there should be extra output in verbose mode. - Default value is False. - - @Return: - data: dict - Contains basic informations of the ECMWF grib files, e.g. - 'Ni', 'Nj', 'latitudeOfFirstGridPointInDegrees', - 'longitudeOfFirstGridPointInDegrees', - 'latitudeOfLastGridPointInDegrees', - 'longitudeOfLastGridPointInDegrees', - 'jDirectionIncrementInDegrees', - 'iDirectionIncrementInDegrees' - """ - - data = {} - - # --- open file --- - print("Opening file for getting information data --- %s" % - os.path.basename(ifile)) - - with open(ifile) as f: - - # load first message from file - gid = codes_grib_new_from_file(f) - - # information needed from grib message - keys = ['Ni', - 'Nj', - 'latitudeOfFirstGridPointInDegrees', - 'longitudeOfFirstGridPointInDegrees', - 'latitudeOfLastGridPointInDegrees', - 'longitudeOfLastGridPointInDegrees', - 'jDirectionIncrementInDegrees', - 'iDirectionIncrementInDegrees'] - - if verb: - print '\nInformations are: ' - for key in keys: - # Get the value of the key in a grib message. - data[key] = codes_get(gid, key) - if verb: - print "%s = %s" % (key, data[key]) - if verb: - print '\n' - - # Free the memory for the message referred as gribid. - codes_release(gid) - - return data - -def get_files_per_date(files, datelist): - ''' - @Description: - The filenames contain dates which are used to select a list - of files for a specific time period specified in datelist. - - @Input: - files: instance of UioFiles - For description see class documentation. - It contains the attribute "files" which is a list of pathes - to filenames. - - datelist: list of datetimes - Contains the list of dates which should be processed for plotting. - - @Return: - filelist: list of strings - Contains the selected files for the time period. - ''' - - filelist = [] - for filename in files: - filedate = filename[-8:] - ddate = datetime.datetime.strptime(filedate, '%y%m%d%H') - if ddate in datelist: - filelist.append(filename) - - return filelist - -def plot_retrieved(c): - ''' - @Description: - Reads GRIB data from a specified time period, a list of levels - and a specified list of parameter. - - @Input: - c: instance of class ControlFile - Contains all necessary information of a CONTROL file. The parameters - are: DAY1, DAY2, DTIME, MAXSTEP, TYPE, TIME, STEP, CLASS, STREAM, - NUMBER, EXPVER, GRID, LEFT, LOWER, UPPER, RIGHT, LEVEL, LEVELIST, - RESOL, GAUSS, ACCURACY, OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, - SMOOTH, FORMAT, ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, - ECFSDIR, MAILOPS, MAILFAIL, GRIB2FLEXPART, DEBUG, INPUTDIR, - OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - For more information about format and content of the parameter see - documentation. - - @Return: - <nothing> - ''' - start = datetime.datetime.strptime(c.start_date, '%Y%m%d%H') - end = datetime.datetime.strptime(c.end_date, '%Y%m%d%H') - - # create datelist between start and end date - datelist = [start] # initialise datelist with first date - run_date = start - while run_date < end: - run_date += datetime.timedelta(hours=int(c.dtime)) - datelist.append(run_date) - - print 'datelist: ', datelist - - c.paramIds = np.asarray(c.paramIds, dtype='int') - c.levels = np.asarray(c.levels, dtype='int') - c.area = np.asarray(c.area) - - files = UioFiles(c.inputdir, c.prefix+'*') - ifiles = get_files_per_date(files.files, datelist) - ifiles.sort() - - gdict = get_basics(ifiles[0], verb=False) - - fdict = dict() - fmeta = dict() - fstamp = dict() - for p in c.paramIds: - for l in c.levels: - key = '{:0>3}_{:0>3}'.format(p, l) - fdict[key] = [] - fmeta[key] = [] - fstamp[key] = [] - - for filename in ifiles: - f = open(filename) - print "Opening file for reading data --- %s" % filename - fdate = datetime.datetime.strptime(filename[-8:], "%y%m%d%H") - - # Load in memory a grib message from a file. - gid = codes_grib_new_from_file(f) - while gid is not None: - gtype = codes_get(gid, 'type') - paramId = codes_get(gid, 'paramId') - parameterName = codes_get(gid, 'parameterName') - level = codes_get(gid, 'level') - - if paramId in c.paramIds and level in c.levels: - key = '{:0>3}_{:0>3}'.format(paramId, level) - print 'key: ', key - if fstamp[key]: - for i in range(len(fstamp[key])): - if fdate < fstamp[key][i]: - fstamp[key].insert(i, fdate) - fmeta[key].insert(i, [paramId, parameterName, gtype, - fdate, level]) - fdict[key].insert(i, np.flipud(np.reshape( - codes_get_values(gid), - [gdict['Nj'], gdict['Ni']]))) - break - elif fdate > fstamp[key][i] and i == len(fstamp[key])-1: - fstamp[key].append(fdate) - fmeta[key].append([paramId, parameterName, gtype, - fdate, level]) - fdict[key].append(np.flipud(np.reshape( - codes_get_values(gid), - [gdict['Nj'], gdict['Ni']]))) - break - elif fdate > fstamp[key][i] and i != len(fstamp[key])-1 \ - and fdate < fstamp[key][i+1]: - fstamp[key].insert(i, fdate) - fmeta[key].insert(i, [paramId, parameterName, gtype, - fdate, level]) - fdict[key].insert(i, np.flipud(np.reshape( - codes_get_values(gid), - [gdict['Nj'], gdict['Ni']]))) - break - else: - pass - else: - fstamp[key].append(fdate) - fmeta[key].append((paramId, parameterName, gtype, - fdate, level)) - fdict[key].append(np.flipud(np.reshape( - codes_get_values(gid), [gdict['Nj'], gdict['Ni']]))) - - codes_release(gid) - - # Load in memory a grib message from a file. - gid = codes_grib_new_from_file(f) - - f.close() - - for k in fdict.iterkeys(): - print 'fmeta: ', len(fmeta), fmeta - fml = fmeta[k] - fdl = fdict[k] - print 'fm1: ', len(fml), fml - for fd, fm in zip(fdl, fml): - print fm - ftitle = fm[1] + ' {} '.format(fm[-1]) + \ - datetime.datetime.strftime(fm[3], '%Y%m%d%H') - pname = '_'.join(fm[1].split()) + '_{}_'.format(fm[-1]) + \ - datetime.datetime.strftime(fm[3], '%Y%m%d%H') - plot_map(c, fd, fm, gdict, ftitle, pname, 'png') - - for k in fdict.iterkeys(): - fml = fmeta[k] - fdl = fdict[k] - fsl = fstamp[k] - if fdl: - fm = fml[0] - fd = fdl[0] - ftitle = fm[1] + ' {} '.format(fm[-1]) + \ - datetime.datetime.strftime(fm[3], '%Y%m%d%H') - pname = '_'.join(fm[1].split()) + '_{}_'.format(fm[-1]) + \ - datetime.datetime.strftime(fm[3], '%Y%m%d%H') - lat = -20. - lon = 20. - plot_timeseries(c, fdl, fml, fsl, lat, lon, gdict, - ftitle, pname, 'png') - - return - -def plot_timeseries(c, flist, fmetalist, ftimestamps, lat, lon, - gdict, ftitle, filename, fending, show=False): - ''' - @Description: - Creates a timeseries plot for a given lat/lon position. - - @Input: - c: instance of class ControlFile - Contains all necessary information of a CONTROL file. The parameters - are: DAY1, DAY2, DTIME, MAXSTEP, TYPE, TIME, STEP, CLASS, STREAM, - NUMBER, EXPVER, GRID, LEFT, LOWER, UPPER, RIGHT, LEVEL, LEVELIST, - RESOL, GAUSS, ACCURACY, OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, - SMOOTH, FORMAT, ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, - ECFSDIR, MAILOPS, MAILFAIL, GRIB2FLEXPART, DEBUG, INPUTDIR, - OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - For more information about format and content of the parameter see - documentation. - - flist: numpy array, 2d - The actual data values to be plotted from the grib messages. - - fmetalist: list of strings - Contains some meta date for the data field to be plotted: - parameter id, parameter Name, grid type, datetime, level - - ftimestamps: list of datetime - Contains the time stamps. - - lat: float - The latitude for which the timeseries should be plotted. - - lon: float - The longitude for which the timeseries should be plotted. - - gdict: dict - Contains basic informations of the ECMWF grib files, e.g. - 'Ni', 'Nj', 'latitudeOfFirstGridPointInDegrees', - 'longitudeOfFirstGridPointInDegrees', - 'latitudeOfLastGridPointInDegrees', - 'longitudeOfLastGridPointInDegrees', - 'jDirectionIncrementInDegrees', - 'iDirectionIncrementInDegrees' - - ftitle: string - The title of the timeseries. - - filename: string - The time series is stored in a file with this name. - - fending: string - Contains the type of plot, e.g. pdf or png - - show: boolean - Decides if the plot is shown after plotting or hidden. - - @Return: - <nothing> - ''' - print 'plotting timeseries' - - t1 = time.time() - - #llx = gdict['longitudeOfFirstGridPointInDegrees'] - #if llx > 180. : - # llx -= 360. - #lly = gdict['latitudeOfLastGridPointInDegrees'] - #dxout = gdict['iDirectionIncrementInDegrees'] - #dyout = gdict['jDirectionIncrementInDegrees'] - #urx = gdict['longitudeOfLastGridPointInDegrees'] - #ury = gdict['latitudeOfFirstGridPointInDegrees'] - #numxgrid = gdict['Ni'] - #numygrid = gdict['Nj'] - - farr = np.asarray(flist) - #(time, lat, lon) - - #lonindex = linspace(llx, urx, numxgrid) - #latindex = linspace(lly, ury, numygrid) - - ts = farr[:, 0, 0] - - fig = plt.figure(figsize=(12, 6.7)) - - plt.plot(ftimestamps, ts) - plt.title(ftitle) - - plt.savefig(c.outputdir + '/' + filename + '_TS.' + fending, - facecolor=fig.get_facecolor(), - edgecolor='none', - format=fending) - print 'created ', c.outputdir + '/' + filename - if show: - plt.show() - fig.clf() - plt.close(fig) - - print time.time() - t1, 's' - - return - -def plot_map(c, flist, fmetalist, gdict, ftitle, filename, fending, show=False): - ''' - @Description: - Creates a basemap plot with imshow for a given data field. - - @Input: - c: instance of class ControlFile - Contains all necessary information of a CONTROL file. The parameters - are: DAY1, DAY2, DTIME, MAXSTEP, TYPE, TIME, STEP, CLASS, STREAM, - NUMBER, EXPVER, GRID, LEFT, LOWER, UPPER, RIGHT, LEVEL, LEVELIST, - RESOL, GAUSS, ACCURACY, OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, - SMOOTH, FORMAT, ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, - ECFSDIR, MAILOPS, MAILFAIL, GRIB2FLEXPART, DEBUG, INPUTDIR, - OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - For more information about format and content of the parameter see - documentation. - - flist: numpy array, 2d - The actual data values to be plotted from the grib messages. - - fmetalist: list of strings - Contains some meta date for the data field to be plotted: - parameter id, parameter Name, grid type, datetime, level - - gdict: dict - Contains basic informations of the ECMWF grib files, e.g. - 'Ni', 'Nj', 'latitudeOfFirstGridPointInDegrees', - 'longitudeOfFirstGridPointInDegrees', - 'latitudeOfLastGridPointInDegrees', - 'longitudeOfLastGridPointInDegrees', - 'jDirectionIncrementInDegrees', - 'iDirectionIncrementInDegrees' - - ftitle: string - The titel of the plot. - - filename: string - The plot is stored in a file with this name. - - fending: string - Contains the type of plot, e.g. pdf or png - - show: boolean - Decides if the plot is shown after plotting or hidden. - - @Return: - <nothing> - ''' - print 'plotting map' - - t1 = time.time() - - fig = plt.figure(figsize=(12, 6.7)) - #mbaxes = fig.add_axes([0.05, 0.15, 0.8, 0.7]) - - llx = gdict['longitudeOfFirstGridPointInDegrees'] #- 360 - if llx > 180.: - llx -= 360. - lly = gdict['latitudeOfLastGridPointInDegrees'] - #dxout = gdict['iDirectionIncrementInDegrees'] - #dyout = gdict['jDirectionIncrementInDegrees'] - urx = gdict['longitudeOfLastGridPointInDegrees'] - ury = gdict['latitudeOfFirstGridPointInDegrees'] - #numxgrid = gdict['Ni'] - #numygrid = gdict['Nj'] - - m = Basemap(projection='cyl', llcrnrlon=llx, llcrnrlat=lly, - urcrnrlon=urx, urcrnrlat=ury, resolution='i') - - #lw = 0.5 - m.drawmapboundary() - #x = linspace(llx, urx, numxgrid) - #y = linspace(lly, ury, numygrid) - - #xx, yy = m(*meshgrid(x, y)) - - #s = m.contourf(xx, yy, flist) - - s = plt.imshow(flist.T, - extent=(llx, urx, lly, ury), - alpha=1.0, - interpolation='nearest' - #vmin=vn, - #vmax=vx, - #cmap=my_cmap, - #levels=levels, - #cmap=my_cmap, - #norm=LogNorm(vn,vx) - ) - - plt.title(ftitle, y=1.08) - cb = m.colorbar(s, location="right", pad="10%") - cb.set_label('label', size=14) - - thickline = np.arange(lly, ury+1, 10.) - thinline = np.arange(lly, ury+1, 5.) - m.drawparallels(thickline, - color='gray', - dashes=[1, 1], - linewidth=0.5, - labels=[1, 1, 1, 1], - xoffset=1.) - m.drawparallels(np.setdiff1d(thinline, thickline), - color='lightgray', - dashes=[1, 1], - linewidth=0.5, - labels=[0, 0, 0, 0]) - - thickline = np.arange(llx, urx+1, 10.) - thinline = np.arange(llx, urx+1, 5.) - m.drawmeridians(thickline, - color='gray', - dashes=[1, 1], - linewidth=0.5, - labels=[1, 1, 1, 1], - yoffset=1.) - m.drawmeridians(np.setdiff1d(thinline, thickline), - color='lightgray', - dashes=[1, 1], - linewidth=0.5, - labels=[0, 0, 0, 0]) - - m.drawcoastlines() - m.drawcountries() - - plt.savefig(c.outputdir + '/' + filename + '_MAP.' + fending, - facecolor=fig.get_facecolor(), - edgecolor='none', - format=fending) - print 'created ', c.outputdir + '/' + filename - if show: - plt.show() - fig.clf() - plt.close(fig) - - print time.time() - t1, 's' - - return - -def get_plot_args(): - ''' - @Description: - Assigns the command line arguments and reads CONTROL file - content. Apply default values for non mentioned arguments. - - @Input: - <nothing> - - @Return: - args: instance of ArgumentParser - Contains the commandline arguments from script/program call. - - c: instance of class ControlFile - Contains all necessary information of a CONTROL file. The parameters - are: DAY1, DAY2, DTIME, MAXSTEP, TYPE, TIME, STEP, CLASS, STREAM, - NUMBER, EXPVER, GRID, LEFT, LOWER, UPPER, RIGHT, LEVEL, LEVELIST, - RESOL, GAUSS, ACCURACY, OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, - SMOOTH, FORMAT, ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, - ECFSDIR, MAILOPS, MAILFAIL, GRIB2FLEXPART, DEBUG, INPUTDIR, - OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - For more information about format and content of the parameter see - documentation. - ''' - parser = ArgumentParser(description='Plot retrieved GRIB data from ' + \ - 'ECMWF MARS archive', - formatter_class=ArgumentDefaultsHelpFormatter) - -# the most important arguments - parser.add_argument("--start_date", dest="start_date", - help="start date YYYYMMDD") - parser.add_argument("--end_date", dest="end_date", - help="end_date YYYYMMDD") - - parser.add_argument("--start_step", dest="start_step", - help="start step in hours") - parser.add_argument("--end_step", dest="end_step", - help="end step in hours") - -# some arguments that override the default in the CONTROL file - parser.add_argument("--levelist", dest="levelist", - help="vertical levels to be retrieved, e.g. 30/to/60") - parser.add_argument("--area", dest="area", - help="area defined as north/west/south/east") - parser.add_argument("--paramIds", dest="paramIds", - help="parameter IDs") - parser.add_argument("--prefix", dest="prefix", default='EN', - help="output file name prefix") - -# set the working directories - parser.add_argument("--inputdir", dest="inputdir", default=None, - help="root directory for storing intermediate files") - parser.add_argument("--outputdir", dest="outputdir", default=None, - help="root directory for storing output files") - parser.add_argument("--flexpart_root_scripts", dest="flexpart_root_scripts", - help="FLEXPART root directory (to find \ - 'grib2flexpart and COMMAND file)\n \ - Normally flex_extract resides in the scripts directory \ - of the FLEXPART distribution") - - parser.add_argument("--controlfile", dest="controlfile", - default='CONTROL.temp', - help="file with CONTROL parameters") - args = parser.parse_args() - - try: - c = ControlFile(args.controlfile) - except IOError: - try: - c = ControlFile(LOCAL_PYTHON_PATH + args.controlfile) - except IOError: - print 'Could not read CONTROL file "' + args.controlfile + '"' - print 'Either it does not exist or its syntax is wrong.' - print 'Try "' + sys.argv[0].split('/')[-1] + \ - ' -h" to print usage information' - exit(1) - - if args.levelist: - c.levels = args.levelist.split('/') - else: - c.levels = [0] - - if args.area: - c.area = args.area.split('/') - else: - c.area = '[0,0]' - - c.paramIds = args.paramIds.split('/') - - if args.start_step: - c.start_step = int(args.start_step) - else: - c.start_step = 0 - - if args.end_step: - c.end_step = int(args.end_step) - else: - c.end_step = 0 - - c.start_date = args.start_date - c.end_date = args.end_date - - c.prefix = args.prefix - - c.inputdir = args.inputdir - - if args.outputdir: - c.outputdir = args.outputdir - else: - c.outputdir = c.inputdir - - return args, c - -if __name__ == "__main__": - main() diff --git a/python/pythontest/.cache/v/cache/lastfailed b/python/pythontest/.cache/v/cache/lastfailed deleted file mode 100644 index 628a749..0000000 --- a/python/pythontest/.cache/v/cache/lastfailed +++ /dev/null @@ -1,4 +0,0 @@ -{ - "TestTools.py::TestTools::test_init128": true, - "TestTools.py::TestTools::test_to_param_id": true -} \ No newline at end of file diff --git a/python/pythontest/.pytest_cache/README.md b/python/pythontest/.pytest_cache/README.md deleted file mode 100644 index bb78ba0..0000000 --- a/python/pythontest/.pytest_cache/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# pytest cache directory # - -This directory contains data from the pytest's cache plugin, -which provides the `--lf` and `--ff` options, as well as the `cache` fixture. - -**Do not** commit this to version control. - -See [the docs](https://docs.pytest.org/en/latest/cache.html) for more information. diff --git a/python/pythontest/.pytest_cache/v/cache/lastfailed b/python/pythontest/.pytest_cache/v/cache/lastfailed deleted file mode 100644 index 1dc1547..0000000 --- a/python/pythontest/.pytest_cache/v/cache/lastfailed +++ /dev/null @@ -1,3 +0,0 @@ -{ - "TestInstall.py::TestTools::test_un_tarball": true -} \ No newline at end of file diff --git a/python/pythontest/.pytest_cache/v/cache/nodeids b/python/pythontest/.pytest_cache/v/cache/nodeids deleted file mode 100644 index cfcdd4d..0000000 --- a/python/pythontest/.pytest_cache/v/cache/nodeids +++ /dev/null @@ -1,4 +0,0 @@ -[ - "TestInstall.py::TestTools::test_mk_tarball", - "TestInstall.py::TestTools::test_un_tarball" -] \ No newline at end of file diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/UioFiles.py b/python/pythontest/TestInstallTar/flex_extract_v7.1/python/UioFiles.py deleted file mode 100644 index fe69953..0000000 --- a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/UioFiles.py +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Anne Fouilloux (University of Oslo) -# -# @Date: October 2014 -# -# @Change History: -# -# November 2015 - Leopold Haimberger (University of Vienna): -# - modified method list_files to work with glob instead of listdir -# - added pattern search in method list_files -# -# February 2018 - Anne Philipp (University of Vienna): -# - applied PEP8 style guide -# - added documentation -# - optimisation of method list_files since it didn't work correctly -# for sub directories -# - additional speed up of method list_files -# - modified the class so that it is initiated with a pattern instead -# of suffixes. Gives more precision in selection of files. -# -# @License: -# (C) Copyright 2014-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Class Decription: -# The class is for file manipulation. It is initiated with a regular -# expression pattern for this instance and can produce a list of Files -# from the given file pattern. These files can be deleted. -# -# @Class Content: -# - __init__ -# - __str__ -# - __list_files__ -# - delete_files -# -# @Class Attributes: -# - pattern -# - files -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import os -import fnmatch - -# software specific module from flex_extract -#import profiling -from tools import silent_remove, get_list_as_string - -# ------------------------------------------------------------------------------ -# CLASS -# ------------------------------------------------------------------------------ - -class UioFiles(object): - ''' - Class to manipulate files. At initialisation it has the attribute - pattern which stores a regular expression pattern for the files associated - with the instance of the class. - ''' - # -------------------------------------------------------------------------- - # CLASS FUNCTIONS - # -------------------------------------------------------------------------- - def __init__(self, path, pattern): - ''' - @Description: - Assignes a specific pattern for these files. - - @Input: - self: instance of UioFiles - Description see class documentation. - - path: string - Directory where to list the files. - - pattern: string - Regular expression pattern. For example: '*.grb' - - @Return: - <nothing> - ''' - - self.path = path - self.pattern = pattern - self.files = None - - self.__list_files__(self.path) - - return - - #@profiling.timefn - def __list_files__(self, path, callid=0): - ''' - @Description: - Lists all files in the directory with the matching - regular expression pattern. - - @Input: - self: instance of UioFiles - Description see class documentation. - - path: string - Path to the files. - - callid: integer - Id which tells the function if its the first call - or a recursive call. Default and first call is 0. - Everything different from 0 is ment to be a recursive case. - - @Return: - <nothing> - ''' - - # initialize variable in first function call - if callid == 0: - self.files = [] - - # Get the absolute path - path = os.path.abspath(path) - - # get the file list of the path if its not a directory and - # if it contains the pattern - self.files.extend([os.path.join(path, k) for k in os.listdir(path) - if fnmatch.fnmatch(k, self.pattern)]) - - # find possible sub-directories in the path - subdirs = [s for s in os.listdir(path) - if os.path.isdir(os.path.join(path, s))] - - # do recursive calls for sub-direcorties - if subdirs: - for subdir in subdirs: - self.__list_files__(os.path.join(path, subdir), callid=1) - - return - - def __str__(self): - ''' - @Description: - Converts the list of files into a single string. - The entries are sepereated by "," sign. - - @Input: - self: instance of UioFiles - Description see class documentation. - - @Return: - files_string: string - The content of the list as a single string. - ''' - - filenames = [os.path.basename(f) for f in self.files] - files_string = get_list_as_string(filenames, concatenate_sign=', ') - - return files_string - - def delete_files(self): - ''' - @Description: - Deletes the files. - - @Input: - self: instance of UioFiles - Description see class documentation. - - @Return: - <nothing> - ''' - - for old_file in self.files: - silent_remove(old_file) - - return diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/_config.py b/python/pythontest/TestInstallTar/flex_extract_v7.1/python/_config.py deleted file mode 100644 index 4c5751c..0000000 --- a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/_config.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Anne Philipp (University of Vienna) -# -# @Date: August 2018 -# -# @Change History: -# -# @License: -# (C) Copyright 2014-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Description: -# Contains constant value parameter for flex_extract. -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import os -import sys -import inspect - -_VERSION_STR = '7.1' - -# ------------------------------------------------------------------------------ -# EXPLICIT FILENAMES -# ------------------------------------------------------------------------------ - -FLEXEXTRACT_DIRNAME = 'flex_extract_v' + _VERSION_STR -FILE_MARS_REQUESTS = 'mars_requests.dat' -FORTRAN_EXECUTABLE = 'CONVERT2' -FILE_USER_ENVVARS = 'ECMWF_ENV' -TEMPFILE_INSTALL_COMPILEJOB = 'compilejob.temp' -FILE_INSTALL_COMPILEJOB = 'compilejob.ksh' -TEMPFILE_INSTALL_JOB = 'job.temp.o' -TEMPFILE_JOB = 'job.temp' -FILE_JOB_OD = 'job.ksh' -FILE_JOB_OP = 'jopoper.ksh' - -# ------------------------------------------------------------------------------ -# EXPLICIT PATHES -# ------------------------------------------------------------------------------ - -# add path to pythonpath -PATH_LOCAL_PYTHON = os.path.dirname(os.path.abspath( - inspect.getfile(inspect.currentframe()))) -if PATH_LOCAL_PYTHON not in sys.path: - sys.path.append(PATH_LOCAL_PYTHON) - -PATH_FLEXEXTRACT_DIR = os.path.normpath(os.path.dirname(os.path.abspath( - inspect.getfile(inspect.currentframe()))) + '/../') - -PATH_RELATIVE_PYTHON = os.path.relpath(PATH_LOCAL_PYTHON, PATH_FLEXEXTRACT_DIR) - -PATH_TEMPLATES = os.path.join(PATH_FLEXEXTRACT_DIR + os.path.sep + - '_templates') - -PATH_RELATIVE_TEMPLATES = os.path.relpath(PATH_TEMPLATES, PATH_FLEXEXTRACT_DIR) - -# path to gribtable -PATH_GRIBTABLE = os.path.join(PATH_TEMPLATES + os.path.sep + - 'ecmwf_grib1_table_128') - -# path to run directory -PATH_RUN_DIR = os.path.join(PATH_FLEXEXTRACT_DIR + os.path.sep + - 'run') - -# path to directory where all control files are stored -PATH_CONTROLFILES = os.path.join(PATH_RUN_DIR + os.path.sep + - 'control') - -# path to directory where all control files are stored -PATH_JOBSCRIPTS = os.path.join(PATH_RUN_DIR + os.path.sep + - 'jobscripts') - -PATH_FORTRAN_SRC = os.path.join(PATH_FLEXEXTRACT_DIR + os.path.sep + - 'src') - -PATH_RELATIVE_FORTRAN_SRC = os.path.relpath(PATH_FORTRAN_SRC, PATH_FLEXEXTRACT_DIR) - diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/install.py b/python/pythontest/TestInstallTar/flex_extract_v7.1/python/install.py deleted file mode 100755 index ba99427..0000000 --- a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/install.py +++ /dev/null @@ -1,546 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Leopold Haimberger (University of Vienna) -# -# @Date: November 2015 -# -# @Change History: -# -# February 2018 - Anne Philipp (University of Vienna): -# - applied PEP8 style guide -# - added documentation -# - moved install_args_and_control in here -# -# @License: -# (C) Copyright 2015-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Program Functionality: -# Depending on the selected installation environment (locally or on the -# ECMWF server ecgate or cca) the program extracts the commandline -# arguments and the CONTROL file parameter and prepares the corresponding -# environment. The necessary files are collected in a tar-ball and placed -# at the target location. There its untared, the environment variables will -# be set and the Fortran code will be compiled. If the ECMWF environment is -# selected a job script is prepared and submitted for the remaining -# configurations after putting the tar-ball to the target ECMWF server. -# -# @Program Content: -# - main -# - get_install_cmdline_arguments -# - install_via_gateway -# - mk_tarball -# - un_tarball -# - mk_env_vars -# - mk_compilejob -# - mk_job_template -# - delete_convert_build -# - make_convert_build -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import os -import sys -import glob -import subprocess -import inspect -from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter - -# software specific classes and modules from flex_extract -import _config -from ControlFile import ControlFile -from UioFiles import UioFiles -from tools import make_dir, put_file_to_ecserver, submit_job_to_ecserver - - -# ------------------------------------------------------------------------------ -# FUNCTIONS -# ------------------------------------------------------------------------------ -def main(): - ''' - @Description: - Controls the installation process. Calls the installation function - if target is specified. - - @Intput: - <nothing> - - @Return: - <nothing> - ''' - - os.chdir(_config.PATH_LOCAL_PYTHON) - args = get_install_cmdline_arguments() - - try: - c = ControlFile(args.controlfile) - except IOError: - print 'Could not read CONTROL file "' + args.controlfile + '"' - print 'Either it does not exist or its syntax is wrong.' - print 'Try "' + sys.argv[0].split('/')[-1] + \ - ' -h" to print usage information' - exit(1) - - c.assign_args_to_control(args) - c.check_install_conditions() - - install_via_gateway(c) - - return - -def get_install_cmdline_arguments(): - ''' - @Description: - Decomposes the command line arguments and assigns them to variables. - Apply default values for non mentioned arguments. - - @Input: - <nothing> - - @Return: - args: instance of ArgumentParser - Contains the commandline arguments from script/program call. - ''' - parser = ArgumentParser(description='Install flex_extract software locally or \ - on ECMWF machines', - formatter_class=ArgumentDefaultsHelpFormatter) - - parser.add_argument('--target', dest='install_target', default=None, - help="Valid targets: local | ecgate | cca , \ - the latter two are at ECMWF") - parser.add_argument("--makefile", dest="makefile", default=None, - help='Name of Makefile to use for compiling CONVERT2') - parser.add_argument("--ecuid", dest="ecuid", default=None, - help='user id at ECMWF') - parser.add_argument("--ecgid", dest="ecgid", default=None, - help='group id at ECMWF') - parser.add_argument("--gateway", dest="gateway", default=None, - help='name of local gateway server') - parser.add_argument("--destination", dest="destination", default=None, - help='ecaccess destination, e.g. leo@genericSftp') - - parser.add_argument("--flexpart_root_scripts", dest="flexpart_root_scripts", - default=None, help="FLEXPART root directory on ECMWF \ - servers (to find grib2flexpart and COMMAND file)\n\ - Normally flex_extract resides in the scripts directory \ - of the FLEXPART distribution, thus the:") - - # arguments for job submission to ECMWF, only needed by submit.py - parser.add_argument("--job_template", dest='job_template', - default="job.temp.o", - help="job template file for submission to ECMWF") - - parser.add_argument("--controlfile", dest="controlfile", - default='CONTROL.temp', - help="file with CONTROL parameters") - - args = parser.parse_args() - - return args - - -def install_via_gateway(c): - ''' - @Description: - Perform the actual installation on local machine or prepare data - transfer to remote gate and submit a job script which will - install everything on the remote gate. - - @Input: - c: instance of class ControlFile - Contains all necessary information of a CONTROL file. The parameters - are: DAY1, DAY2, DTIME, MAXSTEP, TYPE, TIME, STEP, CLASS, STREAM, - NUMBER, EXPVER, GRID, LEFT, LOWER, UPPER, RIGHT, LEVEL, LEVELIST, - RESOL, GAUSS, ACCURACY, OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, - SMOOTH, FORMAT, ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, - ECFSDIR, MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR - For more information about format and content of the parameter see - documentation. - - @Return: - <nothing> - ''' - import tarfile - - ecd = _config.PATH_FLEXEXTRACT_DIR - tarball_name = _config.FLEXEXTRACT_DIRNAME + '.tar' - tar_file = os.path.join(ecd + os.path.sep + tarball_name) - - target_dirname = _config.FLEXEXTRACT_DIRNAME - fortran_executable = _config.FORTRAN_EXECUTABLE - - if c.install_target.lower() != 'local': # ecgate or cca - - mk_compilejob(c.makefile, c.install_target, c.ecuid, c.ecgid, - c.flexpart_root_scripts) - - mk_job_template(c.ecuid, c.ecgid, c.gateway, - c.destination, c.flexpart_root_scripts) - - mk_env_vars(c.ecuid, c.ecgid, c.gateway, c.destination) - - mk_tarball(tar_file) - - put_file_to_ecserver(ecd, tarball_name, c.install_target, - c.ecuid, c.ecgid) - - submit_job_to_ecserver(c.install_target, - os.path.join(_config.PATH_JOBSCRIPTS + - os.path.sep + - _config.FILE_INSTALL_COMPILEJOB)) - - print('job compilation script has been submitted to ecgate for ' + - 'installation in ' + c.flexpart_root_scripts + - '/' + target_dirname) - print('You should get an email with subject "flexcompile" within ' + - 'the next few minutes!') - - else: #local - if not c.flexpart_root_scripts or c.flexpart_root_scripts == '../': - #install_dir = c.flexpart_root_scripts - print('WARNING: FLEXPART_ROOT_SCRIPTS has not been specified') - print('There will be only the compilation of the Fortran program' + - ' in ' + _config.PATH_FORTRAN_SRC) - os.chdir(_config.PATH_FORTRAN_SRC) - else: # creates the target working directory for flex_extract - c.flexpart_root_scripts = os.path.expandvars(os.path.expanduser( - c.flexpart_root_scripts)) - if os.path.abspath(ecd) != os.path.abspath(c.flexpart_root_scripts): - mk_tarball(tar_file) - make_dir(os.path.join(c.flexpart_root_scripts + os.path.sep + - target_dirname)) - os.chdir(os.path.join(c.flexpart_root_scripts + os.path.sep + - target_dirname)) - un_tarball(tar_file) - os.chdir(os.path.join(c.flexpart_root_scripts + os.path.sep + - target_dirname + os.path.sep + - _config.PATH_RELATIVE_FORTRAN_SRC)) - - # Create Fortran executable - CONVERT2 - print('Install ' + target_dirname + ' software at ' + - c.install_target + ' in directory ' + - os.path.abspath(c.flexpart_root_scripts) + '\n') - - delete_convert_build('.') - make_convert_build('.', c.makefile) - - os.chdir(ecd) - if os.path.isfile(tar_file): - os.remove(tar_file) - - return - -def mk_tarball(tarball_path): - ''' - @Description: - Creates a tarball with all necessary files which need to be sent to the - installation directory. - It does not matter if this is local or remote. - Collects all python files, the Fortran source and makefiles, - the ECMWF_ENV file, the CONTROL files as well as the - template files. - - @Input: - tarball_path: string - The complete path to the tar file which will contain all - relevant data for flex_extract. - - @Return: - <nothing> - ''' - import tarfile - from glob import glob - - print('Create tarball ...') - - # change to FLEXEXTRACT directory so that the tar can contain - # relative pathes to the files and directories - ecd = _config.PATH_FLEXEXTRACT_DIR + '/' - os.chdir(ecd) - - # get lists of the files to be added to the tar file - ECMWF_ENV_FILE = [os.path.join(_config.PATH_RELATIVE_PYTHON + - os.path.sep + _config.FILE_USER_ENVVARS)] - pyfiles = [os.path.relpath(x,ecd) - for x in glob(_config.PATH_LOCAL_PYTHON + - os.path.sep + '*py')] - controlfiles = [os.path.relpath(x,ecd) - for x in glob(_config.PATH_CONTROLFILES + - os.path.sep + 'CONTROL*')] - tempfiles = [os.path.relpath(x,ecd) - for x in glob(_config.PATH_TEMPLATES)] - ffiles = [os.path.relpath(x,ecd) - for x in glob(_config.PATH_FORTRAN_SRC + - os.path.sep + '*.f*')] - hfiles = [os.path.relpath(x,ecd) - for x in glob(_config.PATH_FORTRAN_SRC + - os.path.sep + '*.h')] - makefiles = [os.path.relpath(x,ecd) - for x in glob(_config.PATH_FORTRAN_SRC + - os.path.sep + 'Makefile*')] - - # concatenate single lists to one for a better looping - filelist = pyfiles + controlfiles + tempfiles + ffiles + hfiles + \ - makefiles + ECMWF_ENV_FILE - - # create installation tar-file - try: - with tarfile.open(tarball_path, "w:gz") as tar_handle: - for file in filelist: - tar_handle.add(file) - - except subprocess.CalledProcessError as e: - print('... ERROR CODE:\n ... ' + str(e.returncode)) - print('... ERROR MESSAGE:\n ... ' + str(e)) - - sys.exit('... could not make installation tar ball!') - - return - - -def un_tarball(tarball_path): - ''' - @Description: - Extracts the given tarball into current directory. - - @Input: - tarball_path: string - The complete path to the tar file which will contain all - relevant data for flex_extract. - - @Return: - <nothing> - ''' - import tarfile - - print('Untar ...') - - with tarfile.open(tarball_path) as tar_handle: - tar_handle.extractall() - - return - -def mk_env_vars(ecuid, ecgid, gateway, destination): - ''' - @Description: - Creates a file named ECMWF_ENV which contains the - necessary environmental variables at ECMWF servers. - - @Input: - ecuid: string - The user id on ECMWF server. - - ecgid: string - The group id on ECMWF server. - - gateway: string - The gateway server the user is using. - - destination: string - The remote destination which is used to transfer files - from ECMWF server to local gateway server. - - @Return: - <nothing> - ''' - - with open(os.path.join(_config.PATH_LOCAL_PYTHON + os.path.sep + - _config.FILE_USER_ENVVARS), 'w') as fo: - fo.write('ECUID ' + ecuid + '\n') - fo.write('ECGID ' + ecgid + '\n') - fo.write('GATEWAY ' + gateway + '\n') - fo.write('DESTINATION ' + destination + '\n') - - return - -def mk_compilejob(makefile, target, ecuid, ecgid, fp_root): - ''' - @Description: - Modifies the original job template file so that it is specified - for the user and the environment were it will be applied. Result - is stored in a new file "job.temp" in the python directory. - - @Input: - makefile: string - Name of the makefile which should be used to compile FORTRAN - CONVERT2 program. - - target: string - The target where the installation should be done, e.g. the queue. - - ecuid: string - The user id on ECMWF server. - - ecgid: string - The group id on ECMWF server. - - fp_root: string - Path to the root directory of FLEXPART environment or flex_extract - environment. - - @Return: - <nothing> - ''' - - template = os.path.join(_config.PATH_TEMPLATES + os.path.sep + - _config.TEMPFILE_INSTALL_COMPILEJOB) - with open(template) as f: - fdata = f.read().split('\n') - - compilejob = os.path.join(_config.PATH_JOBSCRIPTS + os.path.sep + - _config.FILE_INSTALL_COMPILEJOB) - with open(compilejob, 'w') as fo: - for data in fdata: - if 'MAKEFILE=' in data: - data = 'export MAKEFILE=' + makefile - elif 'FLEXPART_ROOT_SCRIPTS=' in data: - if fp_root != '../': - data = 'export FLEXPART_ROOT_SCRIPTS=' + fp_root - else: - data = 'export FLEXPART_ROOT_SCRIPTS=$HOME' - elif target.lower() != 'local': - if '--workdir' in data: - data = '#SBATCH --workdir=/scratch/ms/' + \ - ecgid + '/' + ecuid - elif '##PBS -o' in data: - data = '##PBS -o /scratch/ms/' + ecgid + '/' + ecuid + \ - 'flex_ecmwf.$Jobname.$Job_ID.out' - elif 'FLEXPART_ROOT_SCRIPTS=' in data: - if fp_root != '../': - data = 'export FLEXPART_ROOT_SCRIPTS=' + fp_root - else: - data = 'export FLEXPART_ROOT_SCRIPTS=$HOME' - fo.write(data + '\n') - - return - -def mk_job_template(ecuid, ecgid, gateway, destination, fp_root): - ''' - @Description: - Modifies the original job template file so that it is specified - for the user and the environment were it will be applied. Result - is stored in a new file "job.temp" in the python directory. - - @Input: - ecuid: string - The user id on ECMWF server. - - ecgid: string - The group id on ECMWF server. - - gateway: string - The gateway server the user is using. - - destination: string - The remote destination which is used to transfer files - from ECMWF server to local gateway server. - - fp_root: string - Path to the root directory of FLEXPART environment or flex_extract - environment. - - @Return: - <nothing> - ''' - ec_python_rel_path = _config.FLEXEXTRACT_DIRNAME + '/' + \ - _config.PATH_RELATIVE_PYTHON - - template = os.path.join(_config.PATH_TEMPLATES + os.path.sep + - _config.TEMPFILE_INSTALL_JOB) - with open(template) as f: - fdata = f.read().split('\n') - - jobfile_temp = os.path.join(_config.PATH_JOBSCRIPTS + os.path.sep + - _config.TEMPFILE_JOB) - with open(jobfile_temp, 'w') as fo: - for data in fdata: - if '--workdir' in data: - data = '#SBATCH --workdir=/scratch/ms/' + ecgid + \ - '/' + ecuid - elif '##PBS -o' in data: - data = '##PBS -o /scratch/ms/' + ecgid + '/' + \ - ecuid + 'flex_ecmwf.$Jobname.$Job_ID.out' - elif 'export PATH=${PATH}:' in data: - data += fp_root + '/' + ec_python_rel_path - - fo.write(data + '\n') - return - -def delete_convert_build(src_path): - ''' - @Description: - Clean up the Fortran source directory and remove all - build files (e.g. *.o, *.mod and CONVERT2) - - @Input: - src_path: string - Path to the fortran source directory. - - @Return: - <nothing> - ''' - - modfiles = UioFiles(src_path, '*.mod') - objfiles = UioFiles(src_path, '*.o') - exefile = UioFiles(src_path, _config.FORTRAN_EXECUTABLE) - - modfiles.delete_files() - objfiles.delete_files() - exefile.delete_files() - - return - -def make_convert_build(src_path, makefile): - ''' - @Description: - Compiles the Fortran code and generates the executable. - - @Input: - src_path: string - Path to the fortran source directory. - - makefile: string - The name of the makefile which should be used. - - @Return: - <nothing> - ''' - - try: - print('Using makefile: ' + makefile) - p = subprocess.Popen(['make', '-f', - os.path.join(src_path + os.path.sep + makefile)], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - bufsize=1) - pout, perr = p.communicate() - print(pout) - if p.returncode != 0: - print(perr) - print('Please edit ' + makefile + - ' or try another Makefile in the src directory.') - print('Most likely GRIB_API_INCLUDE_DIR, GRIB_API_LIB ' - 'and EMOSLIB must be adapted.') - print('Available Makefiles:') - print(UioFiles(src_path, 'Makefile*')) - sys.exit('Compilation failed!') - except ValueError as e: - print('ERROR: Makefile call failed:') - print(e) - else: - subprocess.check_call(['ls', '-l', - os.path.join(src_path + os.path.sep + - _config.FORTRAN_EXECUTABLE)]) - - return - - -if __name__ == "__main__": - main() diff --git a/python/pythontest/TestInstallTar/test_untar/_templates/compilejob.temp b/python/pythontest/TestInstallTar/test_untar/_templates/compilejob.temp deleted file mode 100644 index 715308b..0000000 --- a/python/pythontest/TestInstallTar/test_untar/_templates/compilejob.temp +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/ksh - -# ON ECGB: -# start with ecaccess-job-submit -queueName ecgb NAME_OF_THIS_FILE on gateway server -# start with sbatch NAME_OF_THIS_FILE directly on machine - -#SBATCH --workdir=/scratch/ms/spatlh00/lh0 -#SBATCH --qos=normal -#SBATCH --job-name=flex_ecmwf -#SBATCH --output=flex_ecmwf.%j.out -#SBATCH --error=flex_ecmwf.%j.out -#SBATCH --mail-type=FAIL -#SBATCH --time=12:00:00 - -## CRAY specific batch requests -##PBS -N flex_ecmwf -##PBS -q ns -##PBS -S /usr/bin/ksh -# -o /scratch/ms/no/sbc/flex_ecmwf.$Jobname.$Job_ID.out -# job output is in .ecaccess_DO_NOT_REMOVE -##PBS -j oe -##PBS -V -##PBS -l EC_threads_per_task=1 -##PBS -l EC_memory_per_task=3200MB - -set -x -export VERSION=7.1 -case $HOST in - *ecg*) - module load python - module unload grib_api - module unload emos - module load grib_api/1.14.5 - module load emos/437-r64 - export FLEXPART_ROOT_SCRIPTS= - export MAKEFILE=Makefile.gfortran - ;; - *cca*) - module switch PrgEnv-cray PrgEnv-intel - module load grib_api - module load emos - module load python - echo ${GROUP} - echo ${HOME} - echo $HOME | awk -F / '{print $1, $2, $3, $4}' - export GROUP=`echo $HOME | awk -F / '{print $4}'` - export SCRATCH=/scratch/ms/${GROUP}/${USER} - export FLEXPART_ROOT_SCRIPTS= - export MAKEFILE=Makefile.CRAY - ;; -esac - -mkdir -p $FLEXPART_ROOT_SCRIPTS/flex_extract_v$VERSION -cd $FLEXPART_ROOT_SCRIPTS/flex_extract_v$VERSION # if FLEXPART_ROOT is not set this means cd to the home directory -tar -xvf $HOME/flex_extract_v$VERSION.tar -cd src -\rm *.o *.mod CONVERT2 -make -f $MAKEFILE >flexcompile 2>flexcompile - -ls -l CONVERT2 >>flexcompile -if [ $? -eq 0 ]; then - echo 'SUCCESS!' >>flexcompile - mail -s flexcompile.$HOST.$$ $USER <flexcompile -else - echo Environment: >>flexcompile - env >> flexcompile - mail -s "ERROR! flexcompile.$HOST.$$" $USER <flexcompile -fi - - - - - - - - - diff --git a/python/pythontest/TestInstallTar/test_untar/_templates/ecmwf_grib1_table_128 b/python/pythontest/TestInstallTar/test_untar/_templates/ecmwf_grib1_table_128 deleted file mode 100644 index b14d7af..0000000 --- a/python/pythontest/TestInstallTar/test_untar/_templates/ecmwf_grib1_table_128 +++ /dev/null @@ -1,197 +0,0 @@ -! -! ECMWFGRIB128.TBL -- GRIB 2 parameter conversion table version 128 -! -!ID# NAME UNITS GNAM SCALE MISSING -! -001 Stream function m**2 s**-1 STRF 0 -9999.00 -002 Velocity potential m**2 s**-1 VPOT 0 -9999.00 -003 Potential temperature K THTA 0 -9999.00 -004 Equivalent potential temperature K THTE 0 -9999.00 -005 Saturated eq. pot. temperature K STHE 0 -9999.00 -!006-010 Reserved for Metview -011 U component of divergent wind m s**-1 UDVW 0 -9999.00 -012 V component of divergent wind m s**-1 VDVW 0 -9999.00 -013 U component of rotational wind m s**-1 URTW 0 -9999.00 -014 V component of rotational wind m s**-1 VRTW 0 -9999.00 -!015-020 Reserved for Metview -021 Unbalanced component of temp. K UCTP 0 -9999.00 -022 Unbal. comp. of log surface pres ln(Pa) UCLN 0 -9999.00 -023 Unbal. comp. of divergence s**-1 UCDV 0 -9999.00 -024 Reserved for future unbal. comp. - X 0 -9999.00 -023 Reserved for future unbal. comp. - X 0 -9999.00 -026 Lake cover (0-1) fraction CL 0 -9999.00 -027 Low vegetation cover (0-1) fraction CVL 0 -9999.00 -028 High vegetation cover (0-1) fraction CVH 0 -9999.00 -029 Type of low vegetation type TVL 0 -9999.00 -030 Type of high vegetation type TVH 0 -9999.00 -031 Sea-ice cover (0-1) fraction CI 0 -9999.00 -032 Snow albedo (0-1) fraction ASN 0 -9999.00 -033 Snow density kg m**-3 RSN 0 -9999.00 -034 Sea surface temperature K SST 0 -9999.00 -035 Ice surface temperature layer 1 K ISTL1 0 -9999.00 -036 Ice surface temperature layer 2 K ISTL2 0 -9999.00 -037 Ice surface temperature layer 3 K ISTL3 0 -9999.00 -038 Ice surface temperature layer 4 K ISTL4 0 -9999.00 -039 Volumetric soil water layer 1 m**3 m**3 SWVL1 0 -9999.00 -040 Volumetric soil water layer 2 m**3 m**3 SWVL2 0 -9999.00 -041 Volumetric soil water layer 3 m**3 m**3 SWVL3 0 -9999.00 -042 Volumetric soil water layer 4 m**3 m**3 SWVL4 0 -9999.00 -043 Soil type type SLT 0 -9999.00 -044 Snow evaporation m (H2O) ES 0 -9999.00 -045 Snowmelt m (H2) SMLT 0 -9999.00 -046 Solar duration s SDUR 0 -9999.00 -047 Direct solar radiation W m**-2 DSRP 0 -9999.00 -048 Magnitude of surface stress N m**-2 s MAGSS 0 -9999.00 -049 10 metre wind gust m s**-1 10FG 0 -9999.00 -050 Large-scale precip. fraction s SLPF 0 -9999.00 -051 Maximum 2 metre temperature K MX2T24 0 -9999.00 -052 Minimum 2 metre temperature K MN2T24 0 -9999.00 -053 Montgomery potential m**2 s**-2 MONT 0 -9999.00 -054 Pressure Pa PRES 0 -9999.00 -055 Mean 2m temp.in past 24 hours K MN2T24 0 -9999.00 -056 Mean 2m dewpt. temp. in past 24h K MN2D24 0 -9999.00 -057 Downward UV radiation at sfc. W m**-2 s UVB 0 -9999.00 -058 Photo. active rad. at sfc. W m**-2 s PAR 0 -9999.00 -059 Convective available pot. energy J kg**-1 CAPE 0 -9999.00 -060 Potential vorticity K m**2 kg**-1 s**-1 PVOR 0 -9999.00 -061 Total precipitation from obs. mm*100+Nobs TPO 0 -9999.00 -062 Observation count count OBCT 0 -9999.00 -063 Start time for skin temp. diff. s TSDIFS 0 -9999.00 -064 Finish time for skin temp. diff. s TSDIFE 0 -9999.00 -065 Skin temperature difference K TSDIF 0 -9999.00 -!66 to 77 Unused -078 Total column liquid water kg m**-2 TCLW 0 -9999.00 -079 Total column ice water kg m**-2 TCIW 0 -9999.00 -!80 to 120 Experimental products (contents may vary) -!121 to 124 Unused -125 Vert. integrated tot. energy J m**-2 COLENR 0 -9999.00 -126 Param. for sensitive area pred. - SENPRM 0 -9999.00 -127 Atmospheric tide - AT 0 -9999.00 -128 Budget values - BV 0 -9999.00 -129 Geopotential m**2 s**-2 Z 0 -9999.00 -130 Temperature K T 0 -9999.00 -131 U velocity m s**-1 U 0 -9999.00 -132 V velocity m s**-1 V 0 -9999.00 -133 Specific humidity kg (H2O) kg**1 Q 0 -9999.00 -134 Surface pressure Pa SP -2 -9999.00 -135 Vertical velocity Pa s**-1 W -2 -9999.00 -136 Total column water kg m**-2 TCW 0 -9999.00 -137 Total column water vapour kg m**-2 TCWV 0 -9999.00 -138 Vorticity (relative) s**-1 VO 0 -9999.00 -139 Soil temperature level 1 K STL1 0 -9999.00 -140 Soil wetness level 1 m (H2O) SWL1 0 -9999.00 -141 Snow depth m (H2O) SD 0 -9999.00 -142 Large scale precipitation m LSP 0 -9999.00 -143 Convective precipitation m CP 0 -9999.00 -144 Snowfall (conv. + strat.) m (H2O) SF 0 -9999.00 -145 Boundary layer dissipation W m**-2 s BLD 0 -9999.00 -146 Surface sensible heat flux W m**-2 s SSHF 0 -9999.00 -147 Surface latent heat flux W m**-2 s SLHF 0 -9999.00 -148 Charnock - CHNK 0 -9999.00 -149 Surface net radiation W m**-2 s SNR 0 -9999.00 -150 Top net radiation W m**-2 s TNR 0 -9999.00 -151 Mean sea level pressure Pa MSLP 0 -9999.00 -152 Logarithm of surface pressure ln(Pa) LNSP 0 -9999.00 -153 Short-wave heating rate K SWHR 0 -9999.00 -154 Long-wave heating rate K LWHR 0 -9999.00 -155 Divergence s**-1 D 0 -9999.00 -156 Height m HGHT 0 -9999.00 -157 Relative humidity % RELH 0 -9999.00 -158 Tendency of surface pressure Pa s**-1 PTND -2 -9999.00 -159 Boundary layer height m ZPBL 0 -9999.00 -160 Standard deviation of orography m SDOR 0 -9999.00 -161 Anisotropy of sub-gridscale oro. - ISOR 0 -9999.00 -162 Angle of sub-gridscale orography rad ANOR 0 -9999.00 -163 Slope of sub-gridscale orography - SLOR 0 -9999.00 -164 Total cloud cover (0-1) fraction TCC 0 -9999.00 -165 10 metre U wind component m s**-1 10U 0 -9999.00 -166 10 metre V wind component m s**-1 10V 0 -9999.00 -167 2 metre temperature K 2T 0 -9999.00 -168 2 metre dewpoint temperature K 2D 0 -9999.00 -169 Surface solar radiation downwards W m**-2 s SSRD 0 -9999.00 -170 Soil temperature level 2 K STL2 0 -9999.00 -171 Soil wetness level 2 m (H2O) SWL2 0 -9999.00 -172 Land-sea mask (0,1) logical LSM 0 -9999.00 -173 Surface roughness m SR 0 -9999.00 -174 Albedo (0-1) fraction ALBD 0 -9999.00 -175 Surface thermal radiation down W m**-2 s STRD 0 -9999.00 -176 Surface solar radiation W m**-2 s SSR 0 -9999.00 -177 Surface thermal radiation W m**-2 s STR 0 -9999.00 -178 Top solar radiation W m**-2 s TSR 0 -9999.00 -179 Top thermal radiation W m**-2 s TTR 0 -9999.00 -180 East-West surface stress N m**-2 s EWSS 0 -9999.00 -181 North-South surface stress N m**-2 s NSSS 0 -9999.00 -182 Evaporation m (H2O) EVAP 0 -9999.00 -183 Soil temperature level 3 K STL3 0 -9999.00 -184 Soil wetness level 3 m (H2O) SWL3 0 -9999.00 -185 Convective cloud cover (0-1) fraction CCC 0 -9999.00 -186 Low cloud cover (0-1) fraction LCC 0 -9999.00 -187 Medium cloud cover (0-1) fraction MCC 0 -9999.00 -188 High cloud cover (0-1) fraction HCC 0 -9999.00 -189 Sunshine duration s SUND 0 -9999.00 -190 E-W comp. of subgrid oro. var. m**2 EWOV 0 -9999.00 -191 N-S comp. of subgrid oro. var. m**2 NSOV 0 -9999.00 -192 NW-SE comp. of subgrid oro. var. m**2 NWOV 0 -9999.00 -193 NE-SW comp. of subgrid oro. var. m**2 NEOV 0 -9999.00 -194 Brightness temperature K BTMP 0 -9999.00 -195 Lat. comp. of gravity wave stress N m**-2 s LGWS 0 -9999.00 -196 Mer. comp. of gravity wave stress N m**-2 s MGWS 0 -9999.00 -197 Gravity wave dissipation W m**-2 s GWD 0 -9999.00 -198 Skin reservoir content m (H2O) SRC 0 -9999.00 -199 Vegetation fraction (0-1) fraction VEG 0 -9999.00 -200 Variance of subgrid orography m**2 VSO 0 -9999.00 -201 Max. 2m temp. since post-process. K MX2T 0 -9999.00 -202 Min. 2m temp. since post-process. K MN2T 0 -9999.00 -203 Ozone mass mixing ratio kg (O3) kg**-1 OZMR 0 -9999.00 -204 Precipiation analysis weights - PAW 0 -9999.00 -205 Runoff m RO 0 -9999.00 -206 Total column ozone kg m**-2 TOZO 0 -9999.00 -207 10 metre wind speed m s**-1 10SI 0 -9999.00 -208 Top net solar rad., clear sky W m**-2 s TSRC 0 -9999.00 -209 Top net thermal rad., clear sky W m**-2 s TTRC 0 -9999.00 -210 Surface net solar rad., clear sky W m**-2 s SSRC 0 -9999.00 -211 Sfc. net thermal rad., clear sky W m**-2 s STRC 0 -9999.00 -212 Solar insolation W m**-2 s SI 0 -9999.00 -213 Unused -214 Diabatic heating by radiation K DHR 0 -9999.00 -215 Diab. heating by vert. diffusion K DHVD 0 -9999.00 -216 Diab. heating by cumulus convec. K DHCC 0 -9999.00 -217 Diab. heating resolved conden. K DHLC 0 -9999.00 -218 Vertical diffusion of zonal wind m s**-1 VDZW 0 -9999.00 -219 Vertical diffusion of mer.. wind m s**-1 VDMW 0 -9999.00 -220 E-W gravity wave drag tendency m s**-1 EWGD 0 -9999.00 -221 N-S gravity wave drag tendency m s**-1 NSGD 0 -9999.00 -222 Convective tendency of zonal wind m s**-1 CTZW 0 -9999.00 -223 Convective tendency of mer. wind m s**-1 CTMW 0 -9999.00 -224 Vertical diffusion of humidity kg (H2O) kg**-1 VDH 0 -9999.00 -225 Humid. tend. by cumulus convec. kg (H2O) kg**-1 HTCC 0 -9999.00 -226 Humid. tend. by resolved conden. kg (H2O) kg**-1 HTLC 0 -9999.00 -227 Change from removing neg. humid. kg (H2O) kg**-1 CRNH 0 -9999.00 -228 Total precipitation m P--M 0 -9999.00 -229 Instantaneous X surface stress N m**-2 IEWS 0 -9999.00 -230 Instantaneous Y surface stress N m**-2 INSS 0 -9999.00 -231 Instantaneous surface heat flux W m**-2 ISHF 0 -9999.00 -232 Instantaneous moisture flux kg m**-2 s IE 0 -9999.00 -233 Apparent surface humidity kg (H2O) kg**-1 ASQ 0 -9999.00 -234 Log of sfc. rough. length (heat) ln(m) LSRH 0 -9999.00 -235 Skin temperature K SKT 0 -9999.00 -236 Soil temperature level 4 K STL4 0 -9999.00 -237 Soil wetness level 4 m (H2O) SWL4 0 -9999.00 -238 Temperature of snow layer K TSN 0 -9999.00 -239 Convective snowfall m (H2O) CSF 0 -9999.00 -240 Large-scale snowfall m (H2O) LSF 0 -9999.00 -241 Accum. cloud frac. tend. (-1 - 1) fraction ACF 0 -9999.00 -242 Accum liquid water tend. (-1 - 1) fraction ALW 0 -9999.00 -243 Forecast albedo (0-1) fraction FAL 0 -9999.00 -244 Forecast surface roughness m FSR 0 -9999.00 -245 Fcst. log of src. rough. (heat) log(m) FLSR 0 -9999.00 -246 Cloud liquid water content kg (H2O) kg**-1 CLWC 0 -9999.00 -247 Cloud ice water content kg kg**-1 CIWC 0 -9999.00 -248 Cloud cover (0-1) fraction CC 0 -9999.00 -249 Accum. ice water tend. (-1 - 1) fraction AIW 0 -9999.00 -250 Ice age (1,0) 0-first 1-multi logical ICE 0 -9999.00 -251 Adiabatic tendency of temperature K ATTE 0 -9999.00 -252 Adiabatic tendency of humidity kg (H2O) kg**-1 ATHE 0 -9999.00 -253 Adiabatic tendency of zonal wind m s**-1 ATZE 0 -9999.00 -254 Adiabatic tendency of mer. wind m s**-1 ATMW 0 -9999.00 -255 Indicates a missing value - MISS 0 -9999.00 \ No newline at end of file diff --git a/python/pythontest/TestInstallTar/test_untar/python/ControlFile.py b/python/pythontest/TestInstallTar/test_untar/python/ControlFile.py deleted file mode 100644 index 59a4752..0000000 --- a/python/pythontest/TestInstallTar/test_untar/python/ControlFile.py +++ /dev/null @@ -1,534 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Leopold Haimberger (University of Vienna) -# -# @Date: November 2015 -# -# @Change History: -# -# February 2018 - Anne Philipp (University of Vienna): -# - applied PEP8 style guide -# - added documentation -# - applied some minor modifications in programming style/structure -# - changed name of class Control to ControlFile for more -# self-explanation naming -# - outsource of class ControlFile -# - initialisation of class attributes ( to avoid high number of -# conditional statements and set default values ) -# - divided assignment of attributes and the check of conditions -# - outsourced the commandline argument assignments to control attributes -# -# @License: -# (C) Copyright 2015-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Class Description: -# The CONTROL file is the steering part of the FLEXPART extraction -# software. All necessary parameters needed to retrieve the data fields -# from the MARS archive for driving FLEXPART are set in a CONTROL file. -# Some specific parameters like the start and end dates can be overwritten -# by the command line parameters, but in generel all parameters needed -# for a complete set of fields for FLEXPART can be set in the CONTROL file. -# -# @Class Content: -# - __init__ -# - __read_controlfile__ -# - __str__ -# - assign_args_to_control -# - assign_envs_to_control -# - check_conditions -# - check_install_conditions -# - to_list -# -# @Class Attributes: -# -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import os -import re -import sys -import inspect - -import _config - -# ------------------------------------------------------------------------------ -# CLASS -# ------------------------------------------------------------------------------ -class ControlFile(object): - ''' - Class containing the information of the flex_extract CONTROL file. - - Contains all the parameters of CONTROL file, which are e.g.: - DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, - STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, - LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, - OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, - ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, - MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, - BASETIME, DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - - For more information about format and content of the parameter - see documentation. - - ''' - - def __init__(self, filename): - ''' - @Description: - Initialises the instance of ControlFile class and defines - all class attributes with default values. Afterwards calls - function __read_controlfile__ to read parameter from - Control file. - - @Input: - self: instance of ControlFile class - Description see class documentation. - - filename: string - Name of CONTROL file. - - @Return: - <nothing> - ''' - - # list of all possible class attributes and their default values - self.controlfile = filename - self.start_date = None - self.end_date = None - self.date_chunk = 3 - self.dtime = None - self.basetime = None - self.maxstep = None - self.type = None - self.time = None - self.step = None - self.marsclass = None - self.stream = None - self.number = 'OFF' - self.expver = None - self.grid = None - self.area = '' - self.left = None - self.lower = None - self.upper = None - self.right = None - self.level = None - self.levelist = None - self.resol = None - self.gauss = 0 - self.accuracy = 24 - self.omega = 0 - self.omegadiff = 0 - self.eta = 0 - self.etadiff = 0 - self.etapar = 77 - self.dpdeta = 1 - self.smooth = 0 - self.format = 'GRIB1' - self.addpar = None - self.prefix = 'EN' - self.cwc = 0 - self.wrf = 0 - self.ecfsdir = 'ectmp:/${USER}/econdemand/' - self.mailfail = ['${USER}'] - self.mailops = ['${USER}'] - self.grib2flexpart = 0 - self.ecstorage = 0 - self.ectrans = 0 - self.inputdir = '../work' - self.outputdir = self.inputdir - self.ecmwfdatadir = None - self.exedir = None - self.flexpart_root_scripts = None - self.makefile = None - self.destination = None - self.gateway = None - self.ecuid = None - self.ecgid = None - self.install_target = None - self.debug = 0 - self.request = 0 - - self.__read_controlfile__() - - return - - def __read_controlfile__(self): - ''' - @Description: - Read CONTROL file and assign all CONTROL file variables. - - @Input: - self: instance of ControlFile class - Description see class documentation. - - @Return: - <nothing> - ''' - from tools import my_error - - # read whole CONTROL file - with open(self.controlfile) as f: - fdata = f.read().split('\n') - - # go through every line and store parameter - for ldata in fdata: - data = ldata.split() - if len(data) > 1: - if 'm_' in data[0].lower(): - data[0] = data[0][2:] - if data[0].lower() == 'class': - data[0] = 'marsclass' - if data[0].lower() == 'day1': - data[0] = 'start_date' - if data[0].lower() == 'day2': - data[0] = 'end_date' - if data[0].lower() == 'addpar': - if '/' in data[1]: - # remove leading '/' sign from addpar content - if data[1][0] == '/': - data[1] = data[1][1:] - dd = data[1].split('/') - data = [data[0]] - for d in dd: - data.append(d) - if len(data) == 2: - if '$' in data[1]: - setattr(self, data[0].lower(), data[1]) - while '$' in data[1]: - i = data[1].index('$') - j = data[1].find('{') - k = data[1].find('}') - var = os.getenv(data[1][j+1:k]) - if var is not None: - data[1] = data[1][:i] + var + data[1][k+1:] - else: - my_error(self.mailfail, - 'Could not find variable ' - + data[1][j+1:k] + ' while reading ' + - self.controlfile) - setattr(self, data[0].lower() + '_expanded', data[1]) - else: - if data[1].lower() != 'none': - setattr(self, data[0].lower(), data[1]) - else: - setattr(self, data[0].lower(), None) - elif len(data) > 2: - setattr(self, data[0].lower(), (data[1:])) - else: - pass - - # script directory - self.ecmwfdatadir = os.path.dirname(os.path.abspath(inspect.getfile( - inspect.currentframe()))) + '/../' - - # Fortran source directory - self.exedir = self.ecmwfdatadir + 'src/' - - return - - def __str__(self): - ''' - @Description: - Prepares a string which have all the ControlFile - class attributes with its associated values. - Each attribute is printed in one line and in - alphabetical order. - - Example: - 'age': 10 - 'color': 'Spotted' - 'kids': 0 - 'legs': 2 - 'name': 'Dog' - 'smell': 'Alot' - - @Input: - self: instance of ControlFile class - Description see class documentation. - - @Return: - string of ControlFile class attributes with their values - ''' - import collections - - attrs = vars(self) - attrs = collections.OrderedDict(sorted(attrs.items())) - - return '\n'.join("%s: %s" % item for item in attrs.items()) - - def assign_args_to_control(self, args): - ''' - @Description: - Overwrites the existing ControlFile instance attributes with - the command line arguments. - - @Input: - self: instance of ControlFile class - Description see class documentation. - - args: instance of ArgumentParser - Contains the commandline arguments from script/program call. - - @Return: - <nothing> - ''' - - # get dictionary of command line parameters and eliminate all - # parameters which are None (were not specified) - args_dict = vars(args) - arguments = {k : args_dict[k] for k in args_dict - if args_dict[k] != None} - - # assign all passed command line arguments to ControlFile instance - for k, v in arguments.iteritems(): - setattr(self, str(k), v) - - return - - def assign_envs_to_control(self, envs): - ''' - @Description: - Assigns the ECMWF environment parameter. - - @Input: - envs: dict of strings - Contains the ECMWF environment parameternames "ECUID", "ECGID", - "DESTINATION" and "GATEWAY" with its corresponding values. - They were read from the file "ECMWF_ENV". - - @Return: - <nothing> - ''' - - for k, v in envs.iteritems(): - setattr(self, str(k).lower(), str(v)) - - return - - def check_conditions(self): - ''' - @Description: - Checks a couple of necessary attributes and conditions, - such as if they exist and contain values. - Otherwise set default values. - - @Input: - self: instance of ControlFile class - Description see class documentation. - - @Return: - <nothing> - ''' - from tools import my_error - import numpy as np - - # check for having at least a starting date - # otherwise program is not allowed to run - if self.start_date is None: - print 'start_date specified neither in command line nor ' + \ - 'in CONTROL file ' + self.controlfile - print 'Try "' + sys.argv[0].split('/')[-1] + \ - ' -h" to print usage information' - sys.exit(1) - - # retrieve just one day if end_date isn't set - if self.end_date is None: - self.end_date = self.start_date - - # assure consistency of levelist and level - if self.levelist is None: - if self.level is None: - print 'Warning: neither levelist nor level ' + \ - 'specified in CONTROL file' - sys.exit(1) - else: - self.levelist = '1/to/' + self.level - else: - if 'to' in self.levelist.lower(): - self.level = self.levelist.split('/')[2] - else: - self.level = self.levelist.split('/')[-1] - - # if area was provided at command line - # decompse area into its 4 components - if self.area: - afloat = '.' in self.area - l = self.area.split('/') - if afloat: - for i, item in enumerate(l): - item = str(int(float(item) * 1000)) - self.upper, self.left, self.lower, self.right = l - - # prepare step for correct usage - if '/' in self.step: - l = self.step.split('/') - if 'to' in self.step.lower(): - if 'by' in self.step.lower(): - ilist = np.arange(int(l[0]), int(l[2]) + 1, int(l[4])) - self.step = ['{:0>3}'.format(i) for i in ilist] - else: - my_error(self.mailfail, self.step + ':\n' + - 'if "to" is used, please use "by" as well') - else: - self.step = l - - # if maxstep wasn't provided - # search for it in the "step" parameter - if self.maxstep is None: - self.maxstep = 0 - for s in self.step: - if int(s) > self.maxstep: - self.maxstep = int(s) - else: - self.maxstep = int(self.maxstep) - - # set root scripts since it is needed later on - if not self.flexpart_root_scripts: - self.flexpart_root_scripts = self.ecmwfdatadir - - if not isinstance(self.mailfail, list): - if ',' in self.mailfail: - self.mailfail = self.mailfail.split(',') - elif ' ' in self.mailfail: - self.mailfail = self.mailfail.split() - else: - self.mailfail = [self.mailfail] - - if not isinstance(self.mailops, list): - if ',' in self.mailops: - self.mailops = self.mailops.split(',') - elif ' ' in self.mailops: - self.mailops = self.mailops.split() - else: - self.mailops = [self.mailops] - - if not self.gateway or not self.destination or \ - not self.ecuid or not self.ecgid: - print '\nEnvironment variables GATWAY, DESTINATION, ECUID and ' + \ - 'ECGID were not set properly!' - print 'Please check for excistence of file "ECMWF_ENV" in the ' + \ - 'python directory!' - sys.exit(1) - - if self.request != 0: - marsfile = os.path.join(_config.PATH_RUN_DIR + os.path.sep + - _config.FILE_MARS_REQUESTS) - if os.path.isfile(marsfile): - os.remove(marsfile) - - # check logical variables for data type - # if its a string change to integer - logicals = ['gauss', 'omega', 'omegadiff', 'eta', 'etadiff', - 'dpdeta', 'cwc', 'wrf', 'grib2flexpart', 'ecstorage', - 'ectrans', 'debug', 'request'] - - for var in logicals: - if not isinstance(getattr(self, var), int): - setattr(self, var, int(getattr(self, var))) - - return - - def check_install_conditions(self): - ''' - @Description: - Checks a couple of necessary attributes and conditions - for the installation such as if they exist and contain values. - Otherwise set default values. - - @Input: - self: instance of ControlFile class - Description see class documentation. - - @Return: - <nothing> - ''' - - if self.install_target and \ - self.install_target not in ['local', 'ecgate', 'cca']: - print('ERROR: unknown or missing installation target ') - print('target: ', self.install_target) - print('please specify correct installation target ' + - '(local | ecgate | cca)') - print('use -h or --help for help') - sys.exit(1) - - if self.install_target and self.install_target != 'local': - if not self.ecgid or not self.ecuid or \ - not self.gateway or not self.destination: - print('Please enter your ECMWF user id and group id as well ' + - 'as the \nname of the local gateway and the ectrans ' + - 'destination ') - print('with command line options --ecuid --ecgid \ - --gateway --destination') - print('Try "' + sys.argv[0].split('/')[-1] + \ - ' -h" to print usage information') - print('Please consult ecaccess documentation or ECMWF user \ - support for further details') - sys.exit(1) - - if not self.flexpart_root_scripts: - self.flexpart_root_scripts = '${HOME}' - else: - self.flexpart_root_scripts = self.flexpart_root_scripts - else: # local - if not self.flexpart_root_scripts: - self.flexpart_root_scripts = '../' - - if not self.makefile: - self.makefile = 'Makefile.gfortran' - - return - - def to_list(self): - ''' - @Description: - Just generates a list of strings containing the attributes and - assigned values except the attributes "_expanded", "exedir", - "ecmwfdatadir" and "flexpart_root_scripts". - - @Input: - self: instance of ControlFile class - Description see class documentation. - - @Return: - l: list - A sorted list of the all ControlFile class attributes with - their values except the attributes "_expanded", "exedir", - "ecmwfdatadir" and "flexpart_root_scripts". - ''' - - import collections - - attrs = collections.OrderedDict(sorted(vars(self).items())) - - l = list() - - for item in attrs.items(): - if '_expanded' in item[0]: - pass - elif 'exedir' in item[0]: - pass - elif 'flexpart_root_scripts' in item[0]: - pass - elif 'ecmwfdatadir' in item[0]: - pass - else: - if isinstance(item[1], list): - stot = '' - for s in item[1]: - stot += s + ' ' - - l.append("%s %s" % (item[0], stot)) - else: - l.append("%s %s" % item) - - return sorted(l) - diff --git a/python/pythontest/TestInstallTar/test_untar/python/ECMWF_ENV b/python/pythontest/TestInstallTar/test_untar/python/ECMWF_ENV deleted file mode 100644 index 5af5772..0000000 --- a/python/pythontest/TestInstallTar/test_untar/python/ECMWF_ENV +++ /dev/null @@ -1,4 +0,0 @@ -ECUID km4a -ECGID at -GATEWAY srvx8.img.univie.ac.at -DESTINATION annep@genericSftp diff --git a/python/pythontest/TestInstallTar/test_untar/python/EcFlexpart.py b/python/pythontest/TestInstallTar/test_untar/python/EcFlexpart.py deleted file mode 100644 index 57b2da6..0000000 --- a/python/pythontest/TestInstallTar/test_untar/python/EcFlexpart.py +++ /dev/null @@ -1,1314 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Anne Fouilloux (University of Oslo) -# -# @Date: October 2014 -# -# @Change History: -# -# November 2015 - Leopold Haimberger (University of Vienna): -# - extended with class Control -# - removed functions mkdir_p, daterange, years_between, months_between -# - added functions darain, dapoly, to_param_id, init128, normal_exit, -# my_error, clean_up, install_args_and_control, -# interpret_args_and_control, -# - removed function __del__ in class EIFLexpart -# - added the following functions in EIFlexpart: -# - create_namelist -# - process_output -# - deacc_fluxes -# - modified existing EIFlexpart - functions for the use in -# flex_extract -# - retrieve also longer term forecasts, not only analyses and -# short term forecast data -# - added conversion into GRIB2 -# - added conversion into .fp format for faster execution of FLEXPART -# (see https://www.flexpart.eu/wiki/FpCtbtoWo4FpFormat) -# -# February 2018 - Anne Philipp (University of Vienna): -# - applied PEP8 style guide -# - added documentation -# - removed function getFlexpartTime in class EcFlexpart -# - outsourced class ControlFile -# - outsourced class MarsRetrieval -# - changed class name from EIFlexpart to EcFlexpart -# - applied minor code changes (style) -# - removed "dead code" , e.g. retrieval of Q since it is not needed -# - removed "times" parameter from retrieve-method since it is not used -# -# @License: -# (C) Copyright 2014-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Class Description: -# FLEXPART needs grib files in a specifc format. All necessary data fields -# for one time step are stored in a single file. The class represents an -# instance with all the parameter and settings necessary for retrieving -# MARS data and modifing them so they are fitting FLEXPART need. The class -# is able to disaggregate the fluxes and convert grid types to the one needed -# by FLEXPART, therefore using the FORTRAN program. -# -# @Class Content: -# - __init__ -# - write_namelist -# - retrieve -# - process_output -# - create -# - deacc_fluxes -# -# @Class Attributes: -# - dtime -# - basetime -# - server -# - marsclass -# - stream -# - resol -# - accuracy -# - number -# - expver -# - glevelist -# - area -# - grid -# - level -# - levelist -# - types -# - dates -# - area -# - gaussian -# - params -# - inputdir -# - outputfilelist -# -#******************************************************************************* -#pylint: disable=unsupported-assignment-operation -# this is disabled because its an error in pylint for this specific case -#pylint: disable=consider-using-enumerate -# this is not useful in this case -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import subprocess -import shutil -import os -import glob -from datetime import datetime, timedelta -import numpy as np -from gribapi import grib_set, grib_index_select, grib_new_from_index, grib_get,\ - grib_write, grib_get_values, grib_set_values, grib_release,\ - grib_index_release, grib_index_get - -# software specific classes and modules from flex_extract -import _config -from GribTools import GribTools -from tools import init128, to_param_id, silent_remove, product, my_error -from MarsRetrieval import MarsRetrieval -import disaggregation - -# ------------------------------------------------------------------------------ -# CLASS -# ------------------------------------------------------------------------------ -class EcFlexpart(object): - ''' - Class to retrieve FLEXPART specific ECMWF data. - ''' - # -------------------------------------------------------------------------- - # CLASS FUNCTIONS - # -------------------------------------------------------------------------- - def __init__(self, c, fluxes=False): - ''' - @Description: - Creates an object/instance of EcFlexpart with the - associated settings of its attributes for the retrieval. - - @Input: - self: instance of EcFlexpart - The current object of the class. - - c: instance of class ControlFile - Contains all the parameters of CONTROL file, which are e.g.: - DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, - STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, - LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, - OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, - ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, - MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME - DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - - For more information about format and content of the parameter - see documentation. - - fluxes: boolean, optional - Decides if the flux parameter settings are stored or - the rest of the parameter list. - Default value is False. - - @Return: - <nothing> - ''' - - # different mars types for retrieving data for flexpart - self.types = dict() - - if c.maxstep > len(c.type): # Pure forecast mode - c.type = [c.type[1]] - c.step = ['{:0>3}'.format(int(c.step[0]))] - c.time = [c.time[0]] - for i in range(1, c.maxstep + 1): - c.type.append(c.type[0]) - c.step.append('{:0>3}'.format(i)) - c.time.append(c.time[0]) - - self.inputdir = c.inputdir - self.basetime = c.basetime - self.dtime = c.dtime - i = 0 - if fluxes and c.maxstep <= 24: - # no forecast beyond one day is needed! - # Thus, prepare flux data manually as usual - # with only forecast fields with start times at 00/12 - # (but without 00/12 fields since these are - # the initialisation times of the flux fields - # and therefore are zero all the time) - self.types[c.type[1]] = {'times': '00/12', 'steps': - '{}/to/12/by/{}'.format(c.dtime, c.dtime)} - else: - for ty, st, ti in zip(c.type, c.step, c.time): - btlist = range(24) - if c.basetime == '12': - btlist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] - if c.basetime == '00': - btlist = [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0] - - if i % int(c.dtime) == 0 and (i in btlist or c.maxstep > 24): - - if ty not in self.types.keys(): - self.types[ty] = {'times': '', 'steps': ''} - - if ti not in self.types[ty]['times']: - if self.types[ty]['times']: - self.types[ty]['times'] += '/' - self.types[ty]['times'] += ti - - if st not in self.types[ty]['steps']: - if self.types[ty]['steps']: - self.types[ty]['steps'] += '/' - self.types[ty]['steps'] += st - i += 1 - - self.marsclass = c.marsclass - self.stream = c.stream - self.number = c.number - self.resol = c.resol - self.accuracy = c.accuracy - self.level = c.level - - if c.levelist: - self.levelist = c.levelist - else: - self.levelist = '1/to/' + c.level - - # for gaussian grid retrieval - self.glevelist = '1/to/' + c.level - - if hasattr(c, 'gaussian') and c.gaussian: - self.gaussian = c.gaussian - else: - self.gaussian = '' - - if hasattr(c, 'expver') and c.expver: - self.expver = c.expver - else: - self.expver = '1' - - if hasattr(c, 'number') and c.number: - self.number = c.number - else: - self.number = '0' - - if 'N' in c.grid: # Gaussian output grid - self.grid = c.grid - self.area = 'G' - else: - self.grid = '{}/{}'.format(int(c.grid) / 1000., int(c.grid) / 1000.) - self.area = '{}/{}/{}/{}'.format(int(c.upper) / 1000., - int(c.left) / 1000., - int(c.lower) / 1000., - int(c.right) / 1000.) - - self.outputfilelist = [] - - - # Now comes the nasty part that deals with the different - # scenarios we have: - # 1) Calculation of etadot on - # a) Gaussian grid - # b) Output grid - # c) Output grid using parameter 77 retrieved from MARS - # 3) Calculation/Retrieval of omega - # 4) Download also data for WRF - - - # Different grids need different retrievals - # SH = Spherical Harmonics, GG = Gaussian Grid, - # OG = Output Grid, ML = MultiLevel, SL = SingleLevel - self.params = {'SH__ML': '', 'SH__SL': '', - 'GG__ML': '', 'GG__SL': '', - 'OG__ML': '', 'OG__SL': '', - 'OG_OROLSM_SL': '', 'OG_acc_SL': ''} - - if fluxes is False: - self.params['SH__SL'] = ['LNSP', 'ML', '1', 'OFF'] - # "SD/MSL/TCC/10U/10V/2T/2D/129/172" - self.params['OG__SL'] = ["141/151/164/165/166/167/168/129/172", \ - 'SFC', '1', self.grid] - if c.addpar: - if c.addpar[0] == '/': - c.addpar = c.addpar[1:] - self.params['OG__SL'][0] += '/' + '/'.join(c.addpar) - - self.params['OG_OROLSM__SL'] = ["160/27/28/173", \ - 'SFC', '1', self.grid] - - self.params['OG__ML'] = ['T/Q', 'ML', self.levelist, self.grid] - - if c.gauss == '0' and c.eta == '1': - # the simplest case - self.params['OG__ML'][0] += '/U/V/77' - elif c.gauss == '0' and c.eta == '0': - # this is not recommended (inaccurate) - self.params['OG__ML'][0] += '/U/V' - elif c.gauss == '1' and c.eta == '0': - # this is needed for data before 2008, or for reanalysis data - self.params['GG__SL'] = ['Q', 'ML', '1', \ - '{}'.format((int(self.resol) + 1) / 2)] - self.params['SH__ML'] = ['U/V/D', 'ML', self.glevelist, 'OFF'] - else: - print('Warning: This is a very costly parameter combination, ' - 'use only for debugging!') - self.params['GG__SL'] = ['Q', 'ML', '1', \ - '{}'.format((int(self.resol) + 1) / 2)] - self.params['GG__ML'] = ['U/V/D/77', 'ML', self.glevelist, \ - '{}'.format((int(self.resol) + 1) / 2)] - - if hasattr(c, 'omega') and c.omega == '1': - self.params['OG__ML'][0] += '/W' - - # add cloud water content if necessary - if hasattr(c, 'cwc') and c.cwc == '1': - self.params['OG__ML'][0] += '/CLWC/CIWC' - - # add vorticity and geopotential height for WRF if necessary - if hasattr(c, 'wrf') and c.wrf == '1': - self.params['OG__ML'][0] += '/Z/VO' - if '/D' not in self.params['OG__ML'][0]: - self.params['OG__ML'][0] += '/D' - #wrf_sfc = 'sp/msl/skt/2t/10u/10v/2d/z/lsm/sst/ci/sd/stl1/ / - # stl2/stl3/stl4/swvl1/swvl2/swvl3/swvl4'.upper() - wrf_sfc = '134/235/167/165/166/168/129/172/34/31/141/ \ - 139/170/183/236/39/40/41/42'.upper() - lwrt_sfc = wrf_sfc.split('/') - for par in lwrt_sfc: - if par not in self.params['OG__SL'][0]: - self.params['OG__SL'][0] += '/' + par - - else: - self.params['OG_acc_SL'] = ["LSP/CP/SSHF/EWSS/NSSS/SSR", \ - 'SFC', '1', self.grid] - - # if needed, add additional WRF specific parameters here - - return - - - def write_namelist(self, c, filename): - ''' - @Description: - Creates a namelist file in the temporary directory and writes - the following values to it: maxl, maxb, mlevel, - mlevelist, mnauf, metapar, rlo0, rlo1, rla0, rla1, - momega, momegadiff, mgauss, msmooth, meta, metadiff, mdpdeta - - @Input: - self: instance of EcFlexpart - The current object of the class. - - c: instance of class ControlFile - Contains all the parameters of CONTROL files, which are e.g.: - DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, - STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, - LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, - OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, - ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, - MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME - DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - - For more information about format and content of the parameter - see documentation. - - filename: string - Name of the namelist file. - - @Return: - <nothing> - ''' - - self.inputdir = c.inputdir - area = np.asarray(self.area.split('/')).astype(float) - grid = np.asarray(self.grid.split('/')).astype(float) - - if area[1] > area[3]: - area[1] -= 360 - maxl = int((area[3] - area[1]) / grid[1]) + 1 - maxb = int((area[0] - area[2]) / grid[0]) + 1 - - with open(self.inputdir + '/' + filename, 'w') as f: - f.write('&NAMGEN\n') - f.write(',\n '.join(['maxl = ' + str(maxl), 'maxb = ' + str(maxb), - 'mlevel = ' + str(self.level), - 'mlevelist = ' + '"' + str(self.levelist) - + '"', - 'mnauf = ' + str(self.resol), - 'metapar = ' + '77', - 'rlo0 = ' + str(area[1]), - 'rlo1 = ' + str(area[3]), - 'rla0 = ' + str(area[2]), - 'rla1 = ' + str(area[0]), - 'momega = ' + str(c.omega), - 'momegadiff = ' + str(c.omegadiff), - 'mgauss = ' + str(c.gauss), - 'msmooth = ' + str(c.smooth), - 'meta = ' + str(c.eta), - 'metadiff = ' + str(c.etadiff), - 'mdpdeta = ' + str(c.dpdeta)])) - - f.write('\n/\n') - - return - - def retrieve(self, server, dates, request, inputdir='.'): - ''' - @Description: - Finalizing the retrieval information by setting final details - depending on grid type. - Prepares MARS retrievals per grid type and submits them. - - @Input: - self: instance of EcFlexpart - The current object of the class. - - server: instance of ECMWFService or ECMWFDataServer - The connection to the ECMWF server. This is different - for member state users which have full access and non - member state users which have only access to the public - data sets. The decision is made from command line argument - "public"; for public access its True (ECMWFDataServer) - for member state users its False (ECMWFService) - - dates: string - Contains start and end date of the retrieval in the format - "YYYYMMDD/to/YYYYMMDD" - - inputdir: string, optional - Path to the directory where the retrieved data is about - to be stored. The default is the current directory ('.'). - - @Return: - <nothing> - ''' - self.dates = dates - self.server = server - self.inputdir = inputdir - oro = False - - for ftype in self.types: - for pk, pv in self.params.iteritems(): - if isinstance(pv, str): - continue - mftype = '' + ftype - mftime = self.types[ftype]['times'] - mfstep = self.types[ftype]['steps'] - mfdate = self.dates - mfstream = self.stream - mftarget = self.inputdir + "/" + ftype + pk + '.' + \ - self.dates.split('/')[0] + '.' + str(os.getppid()) +\ - '.' + str(os.getpid()) + ".grb" - if pk == 'OG__SL': - pass - if pk == 'OG_OROLSM__SL': - if oro is False: - mfstream = 'OPER' - mftype = 'AN' - mftime = '00' - mfstep = '000' - mfdate = self.dates.split('/')[0] - mftarget = self.inputdir + "/" + pk + '.' + mfdate + \ - '.' + str(os.getppid()) + '.' + \ - str(os.getpid()) + ".grb" - oro = True - else: - continue - if pk == 'GG__SL' and pv[0] == 'Q': - area = "" - gaussian = 'reduced' - else: - area = self.area - gaussian = self.gaussian - - # ------ on demand path -------------------------------------------------- - if self.basetime is None: - MR = MarsRetrieval(self.server, - marsclass=self.marsclass, - stream=mfstream, - type=mftype, - levtype=pv[1], - levelist=pv[2], - resol=self.resol, - gaussian=gaussian, - accuracy=self.accuracy, - grid=pv[3], - target=mftarget, - area=area, - date=mfdate, - time=mftime, - number=self.number, - step=mfstep, - expver=self.expver, - param=pv[0]) - - if request == 0: - MR.display_info() - MR.data_retrieve() - elif request == 1: - MR.print_info() - elif request == 2: - MR.print_info() - MR.display_info() - MR.data_retrieve() - else: - print 'Failure' - # ------ operational path ------------------------------------------------ - else: - # check if mars job requests fields beyond basetime. - # If yes eliminate those fields since they may not - # be accessible with user's credentials - if 'by' in mfstep: - sm1 = 2 - else: - sm1 = -1 - - if 'by' in mftime: - tm1 = 2 - else: - tm1 = -1 - - maxdate = datetime.strptime(mfdate.split('/')[-1] + - mftime.split('/')[tm1], - '%Y%m%d%H') - istep = int(mfstep.split('/')[sm1]) - maxtime = maxdate + timedelta(hours=istep) - - elimit = datetime.strptime(mfdate.split('/')[-1] + - self.basetime, '%Y%m%d%H') - - if self.basetime == '12': - # -------------- flux data ---------------------------- - if 'acc' in pk: - - # Strategy: - # if maxtime-elimit >= 24h reduce date by 1, - # if 12h <= maxtime-elimit<12h reduce time for last date - # if maxtime-elimit<12h reduce step for last time - # A split of the MARS job into 2 is likely necessary. - maxtime = elimit - timedelta(hours=24) - mfdate = '/'.join(['/'.join(mfdate.split('/')[:-1]), - datetime.strftime(maxtime, - '%Y%m%d')]) - - MR = MarsRetrieval(self.server, - marsclass=self.marsclass, - stream=self.stream, - type=mftype, - levtype=pv[1], - levelist=pv[2], - resol=self.resol, - gaussian=gaussian, - accuracy=self.accuracy, - grid=pv[3], - target=mftarget, - area=area, - date=mfdate, - time=mftime, - number=self.number, - step=mfstep, - expver=self.expver, - param=pv[0]) - - MR.display_info() - MR.data_retrieve() - - maxtime = elimit - timedelta(hours=12) - mfdate = datetime.strftime(maxtime, '%Y%m%d') - mftime = '00' - mftarget = self.inputdir + "/" + ftype + pk + \ - '.' + mfdate + '.' + str(os.getppid()) +\ - '.' + str(os.getpid()) + ".grb" - - MR = MarsRetrieval(self.server, - marsclass=self.marsclass, - stream=self.stream, - type=mftype, - levtype=pv[1], - levelist=pv[2], - resol=self.resol, - gaussian=gaussian, - accuracy=self.accuracy, - grid=pv[3], - target=mftarget, - area=area, - date=mfdate, - time=mftime, - number=self.number, - step=mfstep, - expver=self.expver, - param=pv[0]) - - MR.display_info() - - MR.data_retrieve() - # -------------- non flux data ------------------------ - else: - MR = MarsRetrieval(self.server, - marsclass=self.marsclass, - stream=self.stream, - type=mftype, - levtype=pv[1], - levelist=pv[2], - resol=self.resol, - gaussian=gaussian, - accuracy=self.accuracy, - grid=pv[3], - target=mftarget, - area=area, - date=mfdate, - time=mftime, - number=self.number, - step=mfstep, - expver=self.expver, - param=pv[0]) - - MR.display_info() - MR.data_retrieve() - else: # basetime == 0 ??? #AP - - maxtime = elimit - timedelta(hours=24) - mfdate = datetime.strftime(maxtime, '%Y%m%d') - mftimesave = ''.join(mftime) - - if '/' in mftime: - times = mftime.split('/') - while ((int(times[0]) + - int(mfstep.split('/')[0]) <= 12) and - (pk != 'OG_OROLSM__SL') and 'acc' not in pk): - times = times[1:] - if len(times) > 1: - mftime = '/'.join(times) - else: - mftime = times[0] - - MR = MarsRetrieval(self.server, - marsclass=self.marsclass, - stream=self.stream, - type=mftype, - levtype=pv[1], - levelist=pv[2], - resol=self.resol, - gaussian=gaussian, - accuracy=self.accuracy, - grid=pv[3], - target=mftarget, - area=area, - date=mfdate, - time=mftime, - number=self.number, - step=mfstep, - expver=self.expver, - param=pv[0]) - - MR.display_info() - MR.data_retrieve() - - if (int(mftimesave.split('/')[0]) == 0 and - int(mfstep.split('/')[0]) == 0 and - pk != 'OG_OROLSM__SL'): - - mfdate = datetime.strftime(elimit, '%Y%m%d') - mftime = '00' - mfstep = '000' - mftarget = self.inputdir + "/" + ftype + pk + \ - '.' + mfdate + '.' + str(os.getppid()) +\ - '.' + str(os.getpid()) + ".grb" - - MR = MarsRetrieval(self.server, - marsclass=self.marsclass, - stream=self.stream, - type=mftype, - levtype=pv[1], - levelist=pv[2], - resol=self.resol, - gaussian=gaussian, - accuracy=self.accuracy, - grid=pv[3], - target=mftarget, - area=area, - date=mfdate, - time=mftime, - number=self.number, - step=mfstep, - expver=self.expver, - param=pv[0]) - - MR.display_info() - MR.data_retrieve() - - if request == 0 or request == 2: - print('MARS retrieve done ... ') - elif request == 1: - print('MARS request printed ...') - - return - - - def process_output(self, c): - ''' - @Description: - The grib files are postprocessed depending on the selection in - CONTROL file. The resulting files are moved to the output - directory if its not equla to the input directory. - The following modifications might be done if - properly switched in CONTROL file: - GRIB2 - Conversion to GRIB2 - ECTRANS - Transfer of files to gateway server - ECSTORAGE - Storage at ECMWF server - GRIB2FLEXPART - Conversion of GRIB files to FLEXPART binary format - - @Input: - self: instance of EcFlexpart - The current object of the class. - - c: instance of class ControlFile - Contains all the parameters of CONTROL file, which are e.g.: - DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, - STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, - LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, - OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, - ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, - MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME - DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - - For more information about format and content of the parameter - see documentation. - - @Return: - <nothing> - - ''' - - print '\n\nPostprocessing:\n Format: {}\n'.format(c.format) - - if c.ecapi is False: - print('ecstorage: {}\n ecfsdir: {}\n'. - format(c.ecstorage, c.ecfsdir)) - if not hasattr(c, 'gateway'): - c.gateway = os.getenv('GATEWAY') - if not hasattr(c, 'destination'): - c.destination = os.getenv('DESTINATION') - print('ectrans: {}\n gateway: {}\n destination: {}\n ' - .format(c.ectrans, c.gateway, c.destination)) - - print 'Output filelist: \n' - print self.outputfilelist - - if c.format.lower() == 'grib2': - for ofile in self.outputfilelist: - p = subprocess.check_call(['grib_set', '-s', 'edition=2, \ - productDefinitionTemplateNumber=8', - ofile, ofile + '_2']) - p = subprocess.check_call(['mv', ofile + '_2', ofile]) - - if int(c.ectrans) == 1 and c.ecapi is False: - for ofile in self.outputfilelist: - p = subprocess.check_call(['ectrans', '-overwrite', '-gateway', - c.gateway, '-remote', c.destination, - '-source', ofile]) - #print('ectrans:', p) - - if int(c.ecstorage) == 1 and c.ecapi is False: - for ofile in self.outputfilelist: - p = subprocess.check_call(['ecp', '-o', ofile, - os.path.expandvars(c.ecfsdir)]) - - if c.outputdir != c.inputdir: - for ofile in self.outputfilelist: - p = subprocess.check_call(['mv', ofile, c.outputdir]) - - # prepare environment for the grib2flexpart run - # to convert grib to flexpart binary - if c.grib2flexpart == '1': - - # generate AVAILABLE file - # Example of AVAILABLE file data: - # 20131107 000000 EN13110700 ON DISC - clist = [] - for ofile in self.outputfilelist: - fname = ofile.split('/') - if '.' in fname[-1]: - l = fname[-1].split('.') - timestamp = datetime.strptime(l[0][-6:] + l[1], - '%y%m%d%H') - timestamp += timedelta(hours=int(l[2])) - cdate = datetime.strftime(timestamp, '%Y%m%d') - chms = datetime.strftime(timestamp, '%H%M%S') - else: - cdate = '20' + fname[-1][-8:-2] - chms = fname[-1][-2:] + '0000' - clist.append(cdate + ' ' + chms + ' '*6 + - fname[-1] + ' '*14 + 'ON DISC') - clist.sort() - with open(c.outputdir + '/' + 'AVAILABLE', 'w') as f: - f.write('\n'.join(clist) + '\n') - - # generate pathnames file - pwd = os.path.abspath(c.outputdir) - with open(pwd + '/pathnames', 'w') as f: - f.write(pwd + '/Options/\n') - f.write(pwd + '/\n') - f.write(pwd + '/\n') - f.write(pwd + '/AVAILABLE\n') - f.write(' = == = == = == = == = == == = \n') - - # create Options dir if necessary - if not os.path.exists(pwd + '/Options'): - os.makedirs(pwd+'/Options') - - # read template COMMAND file - with open(os.path.expandvars(os.path.expanduser( - c.flexpart_root_scripts)) + '/../Options/COMMAND', 'r') as f: - lflist = f.read().split('\n') - - # find index of list where to put in the - # date and time information - # usually after the LDIRECT parameter - i = 0 - for l in lflist: - if 'LDIRECT' in l.upper(): - break - i += 1 - - # insert the date and time information of run start and end - # into the list of lines of COMMAND file - lflist = lflist[:i+1] + \ - [clist[0][:16], clist[-1][:16]] + \ - lflist[i+3:] - - # write the new COMMAND file - with open(pwd + '/Options/COMMAND', 'w') as g: - g.write('\n'.join(lflist) + '\n') - - # change to outputdir and start the grib2flexpart run - # afterwards switch back to the working dir - os.chdir(c.outputdir) - p = subprocess.check_call([ - os.path.expandvars(os.path.expanduser(c.flexpart_root_scripts)) - + '/../FLEXPART_PROGRAM/grib2flexpart', 'useAvailable', '.']) - os.chdir(pwd) - - return - - def create(self, inputfiles, c): - ''' - @Description: - This method is based on the ECMWF example index.py - https://software.ecmwf.int/wiki/display/GRIB/index.py - - An index file will be created which depends on the combination - of "date", "time" and "stepRange" values. This is used to iterate - over all messages in each grib file which were passed through the - parameter "inputfiles" to seperate specific parameters into fort.* - files. Afterwards the FORTRAN program Convert2 is called to convert - the data fields all to the same grid and put them in one file - per unique time step (combination of "date", "time" and - "stepRange"). - - @Input: - self: instance of EcFlexpart - The current object of the class. - - inputfiles: instance of UioFiles - Contains a list of files. - - c: instance of class ControlFile - Contains all the parameters of CONTROL files, which are e.g.: - DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, - STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, - LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, - OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, - ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, - MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME - DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - - For more information about format and content of the parameter - see documentation. - - @Return: - <nothing> - ''' - - table128 = init128(_config.PATH_GRIBTABLE) - wrfpars = to_param_id('sp/mslp/skt/2t/10u/10v/2d/z/lsm/sst/ci/sd/\ - stl1/stl2/stl3/stl4/swvl1/swvl2/swvl3/swvl4', - table128) - - index_keys = ["date", "time", "step"] - indexfile = c.inputdir + "/date_time_stepRange.idx" - silent_remove(indexfile) - grib = GribTools(inputfiles.files) - # creates new index file - iid = grib.index(index_keys=index_keys, index_file=indexfile) - - # read values of index keys - index_vals = [] - for key in index_keys: - index_vals.append(grib_index_get(iid, key)) - print index_vals[-1] - # index_vals looks for example like: - # index_vals[0]: ('20171106', '20171107', '20171108') ; date - # index_vals[1]: ('0', '1200', '1800', '600') ; time - # index_vals[2]: ('0', '12', '3', '6', '9') ; stepRange - - fdict = {'10':None, '11':None, '12':None, '13':None, '16':None, - '17':None, '19':None, '21':None, '22':None, '20':None} - - for prod in product(*index_vals): - # flag for Fortran program CONVERT2 and file merging - convertFlag = False - print 'current prod: ', prod - # e.g. prod = ('20170505', '0', '12') - # ( date ,time, step) - # per date e.g. time = 0, 600, 1200, 1800 - # per time e.g. step = 0, 3, 6, 9, 12 - for i in range(len(index_keys)): - grib_index_select(iid, index_keys[i], prod[i]) - - # get first id from current product - gid = grib_new_from_index(iid) - - # if there is data for this product combination - # prepare some date and time parameter before reading the data - if gid is not None: - # Combine all temporary data files into final grib file if - # gid is at least one time not None. Therefore set convertFlag - # to save information. The fortran program CONVERT2 is also - # only done if convertFlag is True - convertFlag = True - # remove old fort.* files and open new ones - # they are just valid for a single product - for k, f in fdict.iteritems(): - silent_remove(c.inputdir + "/fort." + k) - fdict[k] = open(c.inputdir + '/fort.' + k, 'w') - - cdate = str(grib_get(gid, 'date')) - time = grib_get(gid, 'time') - step = grib_get(gid, 'step') - # create correct timestamp from the three time informations - # date, time, step - timestamp = datetime.strptime(cdate + '{:0>2}'.format(time/100), - '%Y%m%d%H') - timestamp += timedelta(hours=int(step)) - cdateH = datetime.strftime(timestamp, '%Y%m%d%H') - - if c.basetime is not None: - slimit = datetime.strptime(c.start_date + '00', '%Y%m%d%H') - bt = '23' - if c.basetime == '00': - bt = '00' - slimit = datetime.strptime(c.end_date + bt, '%Y%m%d%H')\ - - timedelta(hours=12-int(c.dtime)) - if c.basetime == '12': - bt = '12' - slimit = datetime.strptime(c.end_date + bt, '%Y%m%d%H')\ - - timedelta(hours=12-int(c.dtime)) - - elimit = datetime.strptime(c.end_date + bt, '%Y%m%d%H') - - if timestamp < slimit or timestamp > elimit: - continue - - try: - if c.wrf == '1': - if 'olddate' not in locals(): - fwrf = open(c.outputdir + '/WRF' + cdate + - '.{:0>2}'.format(time) + '.000.grb2', 'w') - olddate = cdate[:] - else: - if cdate != olddate: - fwrf = open(c.outputdir + '/WRF' + cdate + - '.{:0>2}'.format(time) + '.000.grb2', - 'w') - olddate = cdate[:] - except AttributeError: - pass - - # helper variable to remember which fields are already used. - savedfields = [] - while 1: - if gid is None: - break - paramId = grib_get(gid, 'paramId') - gridtype = grib_get(gid, 'gridType') - levtype = grib_get(gid, 'typeOfLevel') - if paramId == 133 and gridtype == 'reduced_gg': - # Specific humidity (Q.grb) is used as a template only - # so we need the first we "meet" - with open(c.inputdir + '/fort.18', 'w') as fout: - grib_write(gid, fout) - elif paramId == 131 or paramId == 132: - grib_write(gid, fdict['10']) - elif paramId == 130: - grib_write(gid, fdict['11']) - elif paramId == 133 and gridtype != 'reduced_gg': - grib_write(gid, fdict['17']) - elif paramId == 152: - grib_write(gid, fdict['12']) - elif paramId == 155 and gridtype == 'sh': - grib_write(gid, fdict['13']) - elif paramId in [129, 138, 155] and levtype == 'hybrid' \ - and c.wrf == '1': - pass - elif paramId == 246 or paramId == 247: - # cloud liquid water and ice - if paramId == 246: - clwc = grib_get_values(gid) - else: - clwc += grib_get_values(gid) - grib_set_values(gid, clwc) - grib_set(gid, 'paramId', 201031) - grib_write(gid, fdict['22']) - elif paramId == 135: - grib_write(gid, fdict['19']) - elif paramId == 77: - grib_write(gid, fdict['21']) - else: - if paramId not in savedfields: - grib_write(gid, fdict['16']) - savedfields.append(paramId) - else: - print 'duplicate ' + str(paramId) + ' not written' - - try: - if c.wrf == '1': - if levtype == 'hybrid': # model layer - if paramId in [129, 130, 131, 132, 133, 138, 155]: - grib_write(gid, fwrf) - else: # sfc layer - if paramId in wrfpars: - grib_write(gid, fwrf) - except AttributeError: - pass - - grib_release(gid) - gid = grib_new_from_index(iid) - - for f in fdict.values(): - f.close() - - # call for CONVERT2 if flag is True - if convertFlag: - pwd = os.getcwd() - os.chdir(c.inputdir) - if os.stat('fort.21').st_size == 0 and int(c.eta) == 1: - print 'Parameter 77 (etadot) is missing, most likely it is \ - not available for this type or date/time\n' - print 'Check parameters CLASS, TYPE, STREAM, START_DATE\n' - my_error(c.mailfail, 'fort.21 is empty while parameter eta \ - is set to 1 in CONTROL file') - - # create the corresponding output file fort.15 - # (generated by CONVERT2) + fort.16 (paramId 167 and 168) - p = subprocess.check_call( - [os.path.expandvars(os.path.expanduser(c.exedir)) + - '/CONVERT2'], shell=True) - os.chdir(pwd) - - # create final output filename, e.g. EN13040500 (ENYYMMDDHH) - fnout = c.inputdir + '/' + c.prefix - if c.maxstep > 12: - suffix = cdate[2:8] + '.{:0>2}'.format(time/100) + \ - '.{:0>3}'.format(step) - else: - suffix = cdateH[2:10] - fnout += suffix - print "outputfile = " + fnout - self.outputfilelist.append(fnout) # needed for final processing - - # create outputfile and copy all data from intermediate files - # to the outputfile (final GRIB files) - orolsm = os.path.basename(glob.glob( - c.inputdir + '/OG_OROLSM__SL.*.' + c.ppid + '*')[0]) - fluxfile = 'flux' + cdate[0:2] + suffix - if c.cwc != '1': - flist = ['fort.15', fluxfile, 'fort.16', orolsm] - else: - flist = ['fort.15', 'fort.22', fluxfile, 'fort.16', orolsm] - - with open(fnout, 'wb') as fout: - for f in flist: - shutil.copyfileobj( - open(c.inputdir + '/' + f, 'rb'), fout) - - if c.omega == '1': - with open(c.outputdir + '/OMEGA', 'wb') as fout: - shutil.copyfileobj( - open(c.inputdir + '/fort.25', 'rb'), fout) - - if hasattr(c, 'wrf') and c.wrf == '1': - fwrf.close() - - grib_index_release(iid) - - return - - def deacc_fluxes(self, inputfiles, c): - ''' - @Description: - Goes through all flux fields in ordered time and de-accumulate - the fields. Afterwards the fields are disaggregated in time. - Different versions of disaggregation is provided for rainfall - data (darain, modified linear) and the surface fluxes and - stress data (dapoly, cubic polynomial). - - @Input: - self: instance of EcFlexpart - The current object of the class. - - inputfiles: instance of UioFiles - Contains a list of files. - - c: instance of class ControlFile - Contains all the parameters of CONTROL file, which are e.g.: - DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, - STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, - LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, - OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, - ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, - MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME - DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - - For more information about format and content of the parameter - see documentation. - - @Return: - <nothing> - ''' - - table128 = init128(_config.PATH_GRIBTABLE) - pars = to_param_id(self.params['OG_acc_SL'][0], table128) - index_keys = ["date", "time", "step"] - indexfile = c.inputdir + "/date_time_stepRange.idx" - silent_remove(indexfile) - grib = GribTools(inputfiles.files) - # creates new index file - iid = grib.index(index_keys=index_keys, index_file=indexfile) - - # read values of index keys - index_vals = [] - for key in index_keys: - key_vals = grib_index_get(iid, key) - print key_vals - # have to sort the steps for disaggregation, - # therefore convert to int first - if key == 'step': - key_vals = [int(k) for k in key_vals] - key_vals.sort() - key_vals = [str(k) for k in key_vals] - index_vals.append(key_vals) - # index_vals looks for example like: - # index_vals[0]: ('20171106', '20171107', '20171108') ; date - # index_vals[1]: ('0', '1200') ; time - # index_vals[2]: (3', '6', '9', '12') ; stepRange - - valsdict = {} - svalsdict = {} - stepsdict = {} - for p in pars: - valsdict[str(p)] = [] - svalsdict[str(p)] = [] - stepsdict[str(p)] = [] - - print 'maxstep: ', c.maxstep - - for prod in product(*index_vals): - # e.g. prod = ('20170505', '0', '12') - # ( date ,time, step) - # per date e.g. time = 0, 1200 - # per time e.g. step = 3, 6, 9, 12 - for i in range(len(index_keys)): - grib_index_select(iid, index_keys[i], prod[i]) - - gid = grib_new_from_index(iid) - if gid is not None: - cdate = grib_get(gid, 'date') - time = grib_get(gid, 'time') - step = grib_get(gid, 'step') - # date+time+step-2*dtime - # (since interpolated value valid for step-2*dtime) - sdate = datetime(year=cdate/10000, - month=(cdate % 10000)/100, - day=(cdate % 100), - hour=time/100) - fdate = sdate + timedelta(hours=step-2*int(c.dtime)) - sdates = sdate + timedelta(hours=step) - elimit = None - else: - break - - if c.maxstep > 12: - fnout = c.inputdir + '/flux' + \ - sdate.strftime('%Y%m%d') + '.{:0>2}'.format(time/100) + \ - '.{:0>3}'.format(step-2*int(c.dtime)) - gnout = c.inputdir + '/flux' + \ - sdate.strftime('%Y%m%d') + '.{:0>2}'.format(time/100) + \ - '.{:0>3}'.format(step-int(c.dtime)) - hnout = c.inputdir + '/flux' + \ - sdate.strftime('%Y%m%d') + '.{:0>2}'.format(time/100) + \ - '.{:0>3}'.format(step) - g = open(gnout, 'w') - h = open(hnout, 'w') - else: - fnout = c.inputdir + '/flux' + fdate.strftime('%Y%m%d%H') - gnout = c.inputdir + '/flux' + (fdate + - timedelta(hours=int(c.dtime)) - ).strftime('%Y%m%d%H') - hnout = c.inputdir + '/flux' + sdates.strftime('%Y%m%d%H') - g = open(gnout, 'w') - h = open(hnout, 'w') - - print "outputfile = " + fnout - f = open(fnout, 'w') - - # read message for message and store relevant data fields - # data keywords are stored in pars - while 1: - if gid is None: - break - cparamId = str(grib_get(gid, 'paramId')) - step = grib_get(gid, 'step') - atime = grib_get(gid, 'time') - ni = grib_get(gid, 'Ni') - nj = grib_get(gid, 'Nj') - if cparamId in valsdict.keys(): - values = grib_get_values(gid) - vdp = valsdict[cparamId] - svdp = svalsdict[cparamId] - sd = stepsdict[cparamId] - - if cparamId == '142' or cparamId == '143': - fak = 1. / 1000. - else: - fak = 3600. - - values = (np.reshape(values, (nj, ni))).flatten() / fak - vdp.append(values[:]) # save the accumulated values - if step <= int(c.dtime): - svdp.append(values[:] / int(c.dtime)) - else: # deaccumulate values - svdp.append((vdp[-1] - vdp[-2]) / int(c.dtime)) - - print(cparamId, atime, step, len(values), - values[0], np.std(values)) - # save the 1/3-hourly or specific values - # svdp.append(values[:]) - sd.append(step) - # len(svdp) correspond to the time - if len(svdp) >= 3: - if len(svdp) > 3: - if cparamId == '142' or cparamId == '143': - values = disaggregation.darain(svdp) - else: - values = disaggregation.dapoly(svdp) - - if not (step == c.maxstep and c.maxstep > 12 \ - or sdates == elimit): - vdp.pop(0) - svdp.pop(0) - else: - if c.maxstep > 12: - values = svdp[1] - else: - values = svdp[0] - - grib_set_values(gid, values) - if c.maxstep > 12: - grib_set(gid, 'step', max(0, step-2*int(c.dtime))) - else: - grib_set(gid, 'step', 0) - grib_set(gid, 'time', fdate.hour*100) - grib_set(gid, 'date', fdate.year*10000 + - fdate.month*100+fdate.day) - grib_write(gid, f) - - if c.basetime is not None: - elimit = datetime.strptime(c.end_date + - c.basetime, '%Y%m%d%H') - else: - elimit = sdate + timedelta(2*int(c.dtime)) - - # squeeze out information of last two steps contained - # in svdp - # if step+int(c.dtime) == c.maxstep and c.maxstep>12 - # or sdates+timedelta(hours = int(c.dtime)) - # >= elimit: - # Note that svdp[0] has not been popped in this case - - if step == c.maxstep and c.maxstep > 12 or \ - sdates == elimit: - - values = svdp[3] - grib_set_values(gid, values) - grib_set(gid, 'step', 0) - truedatetime = fdate + timedelta(hours= - 2*int(c.dtime)) - grib_set(gid, 'time', truedatetime.hour * 100) - grib_set(gid, 'date', truedatetime.year * 10000 + - truedatetime.month * 100 + - truedatetime.day) - grib_write(gid, h) - - #values = (svdp[1]+svdp[2])/2. - if cparamId == '142' or cparamId == '143': - values = disaggregation.darain(list(reversed(svdp))) - else: - values = disaggregation.dapoly(list(reversed(svdp))) - - grib_set(gid, 'step', 0) - truedatetime = fdate + timedelta(hours=int(c.dtime)) - grib_set(gid, 'time', truedatetime.hour * 100) - grib_set(gid, 'date', truedatetime.year * 10000 + - truedatetime.month * 100 + - truedatetime.day) - grib_set_values(gid, values) - grib_write(gid, g) - - grib_release(gid) - - gid = grib_new_from_index(iid) - - f.close() - g.close() - h.close() - - grib_index_release(iid) - - return diff --git a/python/pythontest/TestInstallTar/test_untar/python/GribTools.py b/python/pythontest/TestInstallTar/test_untar/python/GribTools.py deleted file mode 100644 index a68d1a5..0000000 --- a/python/pythontest/TestInstallTar/test_untar/python/GribTools.py +++ /dev/null @@ -1,318 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Anne Fouilloux (University of Oslo) -# -# @Date: July 2014 -# -# @Change History: -# February 2018 - Anne Philipp (University of Vienna): -# - applied PEP8 style guide -# - added documentation -# - changed some naming -# -# @License: -# (C) Copyright 2014-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Class Description: -# The GRIB API provides all necessary tools to work directly with the -# grib files. Nevertheless, the GRIB API tools are very basic and are in -# direct connection with the grib files. This class provides some higher -# functions which apply a set of GRIB API tools together in the respective -# context. So, the class initially contains a list of grib files (their -# names) and the using program then applies the methods directly on the -# class objects without having to think about how the actual GRIB API -# tools have to be arranged. -# -# @Class Content: -# - __init__ -# - get_keys -# - set_keys -# - copy -# - index -# -# @Class Attributes: -# - filenames -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import os -from gribapi import grib_new_from_file, grib_is_defined, grib_get, \ - grib_release, grib_set, grib_write, grib_index_read, \ - grib_index_new_from_file, grib_index_add_file, \ - grib_index_write - -# ------------------------------------------------------------------------------ -# CLASS -# ------------------------------------------------------------------------------ -class GribTools(object): - ''' - Class for GRIB utilities (new methods) based on GRIB API - ''' - # -------------------------------------------------------------------------- - # CLASS FUNCTIONS - # -------------------------------------------------------------------------- - def __init__(self, filenames): - ''' - @Description: - Initialise an object of GribTools and assign a list - of filenames. - - @Input: - filenames: list of strings - A list of filenames. - - @Return: - <nothing> - ''' - - self.filenames = filenames - - return - - - def get_keys(self, keynames, wherekeynames=[], wherekeyvalues=[]): - ''' - @Description: - get keyvalues for a given list of keynames - a where statement can be given (list of key and list of values) - - @Input: - keynames: list of strings - List of keynames. - - wherekeynames: list of strings, optional - Default value is an empty list. - - wherekeyvalues: list of strings, optional - Default value is an empty list. - - @Return: - return_list: list of strings - List of keyvalues for given keynames. - ''' - - fileid = open(self.filenames, 'r') - - return_list = [] - - while 1: - gid_in = grib_new_from_file(fileid) - - if gid_in is None: - break - - if len(wherekeynames) != len(wherekeyvalues): - raise Exception("Number of key values and key names must be \ - the same. Give a value for each keyname!") - - select = True - i = 0 - for wherekey in wherekeynames: - if not grib_is_defined(gid_in, wherekey): - raise Exception("where key was not defined") - - select = (select and (str(wherekeyvalues[i]) == - str(grib_get(gid_in, wherekey)))) - i += 1 - - if select: - llist = [] - for key in keynames: - llist.extend([str(grib_get(gid_in, key))]) - return_list.append(llist) - - grib_release(gid_in) - - fileid.close() - - return return_list - - - def set_keys(self, fromfile, keynames, keyvalues, wherekeynames=[], - wherekeyvalues=[], strict=False, filemode='w'): - ''' - @Description: - Opens the file to read the grib messages and then write - them to a new output file. By default all messages are - written out. Also, the keyvalues of the passed list of - keynames are set or only those meeting the where statement. - (list of key and list of values). - - @Input: - fromfile: string - Filename of the input file to read the grib messages from. - - keynames: list of strings - List of keynames. Default is an empty list. - - keyvalues: list of strings - List of keynames. Default is an empty list. - - wherekeynames: list of strings, optional - Default value is an empty list. - - wherekeyvalues: list of strings, optional - Default value is an empty list. - - strict: boolean, optional - Decides if everything from keynames and keyvalues - is written out the grib file (False) or only those - meeting the where statement (True). Default is False. - - filemode: string, optional - Sets the mode for the output file. Default is "w". - - @Return: - <nothing> - - ''' - fout = open(self.filenames, filemode) - fin = open(fromfile) - - while 1: - gid_in = grib_new_from_file(fin) - - if gid_in is None: - break - - if len(wherekeynames) != len(wherekeyvalues): - raise Exception("Give a value for each keyname!") - - select = True - i = 0 - for wherekey in wherekeynames: - if not grib_is_defined(gid_in, wherekey): - raise Exception("where Key was not defined") - - select = (select and (str(wherekeyvalues[i]) == - str(grib_get(gid_in, wherekey)))) - i += 1 - - if select: - i = 0 - for key in keynames: - grib_set(gid_in, key, keyvalues[i]) - i += 1 - - grib_write(gid_in, fout) - - grib_release(gid_in) - - fin.close() - fout.close() - - return - - def copy(self, filename_in, selectWhere=True, - keynames=[], keyvalues=[], filemode='w'): - ''' - Add the content of another input grib file to the objects file but - only messages corresponding to keys/values passed to the function. - The selectWhere switch decides if to copy the keys equal to (True) or - different to (False) the keynames/keyvalues list passed to the function. - - @Input: - filename_in: string - Filename of the input file to read the grib messages from. - - selectWhere: boolean, optional - Decides if to copy the keynames and values equal to (True) or - different to (False) the keynames/keyvalues list passed to the - function. Default is True. - - keynames: list of strings, optional - List of keynames. Default is an empty list. - - keyvalues: list of strings, optional - List of keynames. Default is an empty list. - - filemode: string, optional - Sets the mode for the output file. Default is "w". - - @Return: - <nothing> - ''' - - fin = open(filename_in) - fout = open(self.filenames, filemode) - - while 1: - gid_in = grib_new_from_file(fin) - - if gid_in is None: - break - - if len(keynames) != len(keyvalues): - raise Exception("Give a value for each keyname!") - - select = True - i = 0 - for key in keynames: - if not grib_is_defined(gid_in, key): - raise Exception("Key was not defined") - - if selectWhere: - select = (select and (str(keyvalues[i]) == - str(grib_get(gid_in, key)))) - else: - select = (select and (str(keyvalues[i]) != - str(grib_get(gid_in, key)))) - i += 1 - - if select: - grib_write(gid_in, fout) - - grib_release(gid_in) - - fin.close() - fout.close() - - return - - def index(self, index_keys=["mars"], index_file="my.idx"): - ''' - @Description: - Create index file from a list of files if it does not exist or - read an index file. - - @Input: - index_keys: list of strings, optional - Contains the list of key parameter names from - which the index is to be created. - Default is a list with a single entry string "mars". - - index_file: string, optional - Filename where the indices are stored. - Default is "my.idx". - - @Return: - iid: integer - Grib index id. - ''' - print "... index will be done" - iid = None - - if os.path.exists(index_file): - iid = grib_index_read(index_file) - print "Use existing index file: %s " % (index_file) - else: - for filename in self.filenames: - print "Inputfile: %s " % (filename) - if iid is None: - iid = grib_index_new_from_file(filename, index_keys) - else: - grib_index_add_file(iid, filename) - - if iid is not None: - grib_index_write(iid, index_file) - - print '... index done' - - return iid diff --git a/python/pythontest/TestInstallTar/test_untar/python/MarsRetrieval.py b/python/pythontest/TestInstallTar/test_untar/python/MarsRetrieval.py deleted file mode 100644 index fa4012c..0000000 --- a/python/pythontest/TestInstallTar/test_untar/python/MarsRetrieval.py +++ /dev/null @@ -1,419 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Anne Fouilloux (University of Oslo) -# -# @Date: October 2014 -# -# @Change History: -# -# November 2015 - Leopold Haimberger (University of Vienna): -# - optimized display_info -# - optimized data_retrieve and seperate between python and shell -# script call -# -# February 2018 - Anne Philipp (University of Vienna): -# - applied PEP8 style guide -# - added documentation -# - applied some minor modifications in programming style/structure -# -# @License: -# (C) Copyright 2015-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Class Description: -# A MARS revtrieval has a specific syntax with a selection of keywords and -# their corresponding values. This class provides the necessary functions -# by displaying the selected parameters and their values and the actual -# retrievement of the data through a mars request or a Python web api -# interface. The initialization already expects all the keyword values. -# -# @Class Content: -# - __init__ -# - display_info -# - data_retrieve -# -# @Class Attributes: -# - server -# - marsclass -# - dtype -# - levtype -# - levelist -# - repres -# - date -# - resol -# - stream -# - area -# - time -# - step -# - expver -# - number -# - accuracy -# - grid -# - gaussian -# - target -# - param -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import subprocess -import os - -import _config -# ------------------------------------------------------------------------------ -# CLASS -# ------------------------------------------------------------------------------ -class MarsRetrieval(object): - ''' - Class for submitting MARS retrievals. - - A description of MARS keywords/arguments and examples of their - values can be found here: - https://software.ecmwf.int/wiki/display/UDOC/\ - Identification+keywords#Identificationkeywords-class - - ''' - - def __init__(self, server, marsclass="ei", type="", levtype="", - levelist="", repres="", date="", resol="", stream="", - area="", time="", step="", expver="1", number="", - accuracy="", grid="", gaussian="", target="", - param=""): - ''' - @Description: - Initialises the instance of the MarsRetrieval class and - defines and assigns a set of the necessary retrieval parameters - for the FLEXPART input data. - A description of MARS keywords/arguments, their dependencies - on each other and examples of their values can be found here: - - https://software.ecmwf.int/wiki/display/UDOC/MARS+keywords - - @Input: - self: instance of MarsRetrieval - For description see class documentation. - - server: instance of ECMWFService (from ECMWF Web-API) - This is the connection to the ECMWF data servers. - It is needed for the pythonic access of ECMWF data. - - marsclass: string, optional - Characterisation of dataset. E.g. EI (ERA-Interim), - E4 (ERA40), OD (Operational archive), ea (ERA5). - Default is the ERA-Interim dataset "ei". - - type: string, optional - Determines the type of fields to be retrieved. - Selects between observations, images or fields. - Examples for fields: Analysis (an), Forecast (fc), - Perturbed Forecast (pf), Control Forecast (cf) and so on. - Default is an empty string. - - levtype: string, optional - Denotes type of level. Has a direct implication on valid - levelist values! - E.g. model level (ml), pressure level (pl), surface (sfc), - potential vorticity (pv), potential temperature (pt) - and depth (dp). - Default is an empty string. - - levelist: string, optional - Specifies the required levels. It has to have a valid - correspondence to the selected levtype. - Examples: model level: 1/to/137, pressure levels: 500/to/1000 - Default is an empty string. - - repres: string, optional - Selects the representation of the archived data. - E.g. sh - spherical harmonics, gg - Gaussian grid, - ll - latitude/longitude, ... - Default is an empty string. - - date: string, optional - Specifies the Analysis date, the Forecast base date or - Observations date. Valid formats are: - Absolute as YYYY-MM-DD or YYYYMMDD. - Default is an empty string. - - resol: string, optional - Specifies the desired triangular truncation of retrieved data, - before carrying out any other selected post-processing. - The default is automatic truncation (auto), by which the lowest - resolution compatible with the value specified in grid is - automatically selected for the retrieval. - Users wanting to perform post-processing from full spectral - resolution should specify Archived Value (av). - The following are examples of existing resolutions found in - the archive: 63, 106, 159, 213, 255, 319, 399, 511, 799 or 1279. - This keyword has no meaning/effect if the archived data is - not in spherical harmonics representation. - The best selection can be found here: - https://software.ecmwf.int/wiki/display/UDOC/\ - Retrieve#Retrieve-Truncationbeforeinterpolation - Default is an empty string. - - stream: string, optional - Identifies the forecasting system used to generate the data. - E.g. oper (Atmospheric model), enfo (Ensemble forecats), ... - Default is an empty string. - - area: string, optional - Specifies the desired sub-area of data to be extracted. - Areas can be defined to wrap around the globe. - - Latitude values must be given as signed numbers, with: - north latitudes (i.e. north of the equator) - being positive (e.g: 40.5) - south latitutes (i.e. south of the equator) - being negative (e.g: -50.5) - Longtitude values must be given as signed numbers, with: - east longitudes (i.e. east of the 0 degree meridian) - being positive (e.g: 35.0) - west longitudes (i.e. west of the 0 degree meridian) - being negative (e.g: -20.5) - - E.g.: North/West/South/East - Default is an empty string. - - time: string, optional - Specifies the time of the data in hours and minutes. - Valid values depend on the type of data: Analysis time, - Forecast base time or First guess verification time - (all usually at synoptic hours: 00, 06, 12 and 18 ). - Observation time (any combination in hours and minutes is valid, - subject to data availability in the archive). - The syntax is HHMM or HH:MM. If MM is omitted it defaults to 00. - Default is an empty string. - - step: string, optional - Specifies the forecast time step from forecast base time. - Valid values are hours (HH) from forecast base time. It also - specifies the length of the forecast which verifies at - First Guess time. - E.g. 1/3/6-hourly - Default is an empty string. - - expver: string, optional - The version of the dataset. Each experiment is assigned a - unique code (version). Production data is assigned 1 or 2, - and experimental data in Operations 11, 12 ,... - Research or Member State's experiments have a four letter - experiment identifier. - Default is "1". - - number: string, optional - Selects the member in ensemble forecast run. (Only then it - is necessary.) It has a different meaning depending on - the type of data. - E.g. Perturbed Forecasts: specifies the Ensemble forecast member - Default is an empty string. - - accuracy: string, optional - Specifies the number of bits per value to be used in the - generated GRIB coded fields. - A positive integer may be given to specify the preferred number - of bits per packed value. This must not be greater than the - number of bits normally used for a Fortran integer on the - processor handling the request (typically 32 or 64 bit). - Within a compute request the accuracy of the original fields - can be passed to the result field by specifying accuracy=av. - Default is an empty string. - - grid: string, optional - Specifies the output grid which can be either a Gaussian grid - or a Latitude/Longitude grid. MARS requests specifying - grid=av will return the archived model grid. - - Lat/Lon grid: The grid spacing needs to be an integer - fraction of 90 degrees e.g. grid = 0.5/0.5 - - Gaussian grid: specified by a letter denoting the type of - Gaussian grid followed by an integer (the grid number) - representing the number of lines between the Pole and Equator, - e.g. - grid = F160 - full (or regular) Gaussian grid with - 160 latitude lines between the pole and equator - grid = N320 - ECMWF original reduced Gaussian grid with - 320 latitude lines between the pole and equator, - see Reduced Gaussian Grids for grid numbers used at ECMWF - grid = O640 - ECMWF octahedral (reduced) Gaussian grid with - 640 latitude lines between the pole and equator - Default is an empty string. - - gaussian: string, optional - This parameter is deprecated and should no longer be used. - Specifies the desired type of Gaussian grid for the output. - Valid Gaussian grids are quasi-regular (reduced) or regular. - Keyword gaussian can only be specified together with - keyword grid. Gaussian without grid has no effect. - Default is an empty string. - - target: string, optional - Specifies a file into which data is to be written after - retrieval or manipulation. Path names should always be - enclosed in double quotes. The MARS client supports automatic - generation of multiple target files using MARS keywords - enclosed in square brackets [ ]. If the environment variable - MARS_MULTITARGET_STRICT_FORMAT is set to 1 before calling mars, - the keyword values will be used in the filename as shown by - the ecCodes GRIB tool grib_ls -m, e.g. with - MARS_MULTITARGET_STRICT_FORMAT set to 1 the keywords time, - expver and param will be formatted as 0600, 0001 and 129.128 - rather than 600, 1 and 129. - Default is an empty string. - - param: string, optional - Specifies the meteorological parameter. - The list of meteorological parameters in MARS is extensive. - Their availability is directly related to their meteorological - meaning and, therefore, the rest of directives specified - in the MARS request. - Meteorological parameters can be specified by their - GRIB code (param=130), their mnemonic (param=t) or - full name (param=temperature). - The list of parameter should be seperated by a "/"-sign. - E.g. 130/131/133 - Default is an empty string. - - @Return: - <nothing> - ''' - - self.server = server - self.marsclass = marsclass - self.type = type - self.levtype = levtype - self.levelist = levelist - self.repres = repres - self.date = date - self.resol = resol - self.stream = stream - self.area = area - self.time = time - self.step = step - self.expver = expver - self.number = number - self.accuracy = accuracy - self.grid = grid - self.gaussian = gaussian - self.target = target - self.param = param - - return - - - def display_info(self): - ''' - @Description: - Prints all class attributes and their values. - - @Input: - self: instance of MarsRetrieval - For description see class documentation. - - @Return: - <nothing> - ''' - # Get all class attributes and their values as a dictionary - attrs = vars(self) - - # iterate through all attributes and print them - # with their corresponding values - for item in attrs.items(): - if item[0] in 'server': - pass - else: - print item[0] + ': ' + str(item[1]) - - return - - - def print_info(self): - ''' - ''' - # Get all class attributes and their values as a dictionary - attrs = vars(self) - - # open a file to store all requests to - with open(os.path.join(_config.PATH_RUN_DIR + os.path.sep + - _config.FILE_MARS_REQUESTS), 'a') as f: - f.write('mars\n') - # iterate through all attributes and print them - # with their corresponding values - for item in attrs.items(): - if item[0] in 'server': - pass - else: - f.write(item[0] + ': ' + str(item[1]) + '\n') - f.write('\n\n') - - return - - def data_retrieve(self): - ''' - @Description: - Submits a MARS retrieval. Depending on the existence of - ECMWF Web-API it is submitted via Python or a - subprocess in the Shell. The parameter for the mars retrieval - are taken from the defined class attributes. - - @Input: - self: instance of MarsRetrieval - For description see class documentation. - - @Return: - <nothing> - ''' - # Get all class attributes and their values as a dictionary - attrs = vars(self) - - # convert the dictionary of attributes into a comma - # seperated list of attributes with their values - # needed for the retrieval call - s = 'ret' - for k, v in attrs.iteritems(): - if k in 'server': - continue - if k == 'marsclass': - k = 'class' - if v == '': - continue - if k.lower() == 'target': - target = v - else: - s = s + ',' + k + '=' + str(v) - - # MARS request via Python script - if self.server is not False: - try: - self.server.execute(s, target) - except: - print('MARS Request failed, ' - 'have you already registered at apps.ecmwf.int?') - raise IOError - if os.stat(target).st_size == 0: - print('MARS Request returned no data - please check request') - raise IOError - # MARS request via extra process in shell - else: - s += ',target = "' + target + '"' - p = subprocess.Popen(['mars'], stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, bufsize=1) - pout = p.communicate(input=s)[0] - print pout.decode() - - if 'Some errors reported' in pout.decode(): - print('MARS Request failed - please check request') - raise IOError - - if os.stat(target).st_size == 0: - print('MARS Request returned no data - please check request') - raise IOError - - return diff --git a/python/pythontest/TestInstallTar/test_untar/python/_config.py b/python/pythontest/TestInstallTar/test_untar/python/_config.py deleted file mode 100644 index 4c5751c..0000000 --- a/python/pythontest/TestInstallTar/test_untar/python/_config.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Anne Philipp (University of Vienna) -# -# @Date: August 2018 -# -# @Change History: -# -# @License: -# (C) Copyright 2014-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Description: -# Contains constant value parameter for flex_extract. -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import os -import sys -import inspect - -_VERSION_STR = '7.1' - -# ------------------------------------------------------------------------------ -# EXPLICIT FILENAMES -# ------------------------------------------------------------------------------ - -FLEXEXTRACT_DIRNAME = 'flex_extract_v' + _VERSION_STR -FILE_MARS_REQUESTS = 'mars_requests.dat' -FORTRAN_EXECUTABLE = 'CONVERT2' -FILE_USER_ENVVARS = 'ECMWF_ENV' -TEMPFILE_INSTALL_COMPILEJOB = 'compilejob.temp' -FILE_INSTALL_COMPILEJOB = 'compilejob.ksh' -TEMPFILE_INSTALL_JOB = 'job.temp.o' -TEMPFILE_JOB = 'job.temp' -FILE_JOB_OD = 'job.ksh' -FILE_JOB_OP = 'jopoper.ksh' - -# ------------------------------------------------------------------------------ -# EXPLICIT PATHES -# ------------------------------------------------------------------------------ - -# add path to pythonpath -PATH_LOCAL_PYTHON = os.path.dirname(os.path.abspath( - inspect.getfile(inspect.currentframe()))) -if PATH_LOCAL_PYTHON not in sys.path: - sys.path.append(PATH_LOCAL_PYTHON) - -PATH_FLEXEXTRACT_DIR = os.path.normpath(os.path.dirname(os.path.abspath( - inspect.getfile(inspect.currentframe()))) + '/../') - -PATH_RELATIVE_PYTHON = os.path.relpath(PATH_LOCAL_PYTHON, PATH_FLEXEXTRACT_DIR) - -PATH_TEMPLATES = os.path.join(PATH_FLEXEXTRACT_DIR + os.path.sep + - '_templates') - -PATH_RELATIVE_TEMPLATES = os.path.relpath(PATH_TEMPLATES, PATH_FLEXEXTRACT_DIR) - -# path to gribtable -PATH_GRIBTABLE = os.path.join(PATH_TEMPLATES + os.path.sep + - 'ecmwf_grib1_table_128') - -# path to run directory -PATH_RUN_DIR = os.path.join(PATH_FLEXEXTRACT_DIR + os.path.sep + - 'run') - -# path to directory where all control files are stored -PATH_CONTROLFILES = os.path.join(PATH_RUN_DIR + os.path.sep + - 'control') - -# path to directory where all control files are stored -PATH_JOBSCRIPTS = os.path.join(PATH_RUN_DIR + os.path.sep + - 'jobscripts') - -PATH_FORTRAN_SRC = os.path.join(PATH_FLEXEXTRACT_DIR + os.path.sep + - 'src') - -PATH_RELATIVE_FORTRAN_SRC = os.path.relpath(PATH_FORTRAN_SRC, PATH_FLEXEXTRACT_DIR) - diff --git a/python/pythontest/TestInstallTar/test_untar/python/disaggregation.py b/python/pythontest/TestInstallTar/test_untar/python/disaggregation.py deleted file mode 100644 index aa84eaf..0000000 --- a/python/pythontest/TestInstallTar/test_untar/python/disaggregation.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Anne Philipp (University of Vienna) -# -# @Date: March 2018 -# -# @Change History: -# -# November 2015 - Leopold Haimberger (University of Vienna): -# - migration of the methods dapoly and darain from Fortran -# (flex_extract_v6 and earlier) to Python -# -# April 2018 - Anne Philipp (University of Vienna): -# - applied PEP8 style guide -# - added structured documentation -# - outsourced the disaggregation functions dapoly and darain -# to a new module named disaggregation -# -# @License: -# (C) Copyright 2015-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Module Description: -# disaggregation of deaccumulated flux data from an ECMWF model FG field. -# Initially the flux data to be concerned are: -# - large-scale precipitation -# - convective precipitation -# - surface sensible heat flux -# - surface solar radiation -# - u stress -# - v stress -# Different versions of disaggregation is provided for rainfall -# data (darain, modified linear) and the surface fluxes and -# stress data (dapoly, cubic polynomial). -# -# @Module Content: -# - dapoly -# - darain -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ - -# ------------------------------------------------------------------------------ -# FUNCTIONS -# ------------------------------------------------------------------------------ -def dapoly(alist): - ''' - @Author: P. JAMES - - @Date: 2000-03-29 - - @ChangeHistory: - June 2003 - A. BECK (2003-06-01) - adaptaions - November 2015 - Leopold Haimberger (University of Vienna) - migration from Fortran to Python - - @Description: - Interpolation of deaccumulated fluxes of an ECMWF model FG field - using a cubic polynomial solution which conserves the integrals - of the fluxes within each timespan. - disaggregationregation is done for 4 accumluated timespans which generates - a new, disaggregated value which is output at the central point - of the 4 accumulation timespans. This new point is used for linear - interpolation of the complete timeseries afterwards. - - @Input: - alist: list of size 4, array(2D), type=float - List of 4 timespans as 2-dimensional, horizontal fields. - E.g. [[array_t1], [array_t2], [array_t3], [array_t4]] - - @Return: - nfield: array(2D), type=float - New field which replaces the field at the second position - of the accumulation timespans. - - ''' - pya = (alist[3] - alist[0] + 3. * (alist[1] - alist[2])) / 6. - pyb = (alist[2] + alist[0]) / 2. - alist[1] - 9. * pya / 2. - pyc = alist[1] - alist[0] - 7. * pya / 2. - 2. * pyb - pyd = alist[0] - pya / 4. - pyb / 3. - pyc / 2. - nfield = 8. * pya + 4. * pyb + 2. * pyc + pyd - - return nfield - - -def darain(alist): - ''' - @Author: P. JAMES - - @Date: 2000-03-29 - - @ChangeHistory: - June 2003 - A. BECK (2003-06-01) - adaptaions - November 2015 - Leopold Haimberger (University of Vienna) - migration from Fortran to Python - - @Description: - Interpolation of deaccumulated fluxes of an ECMWF model FG rainfall - field using a modified linear solution which conserves the integrals - of the fluxes within each timespan. - disaggregationregation is done for 4 accumluated timespans which generates - a new, disaggregated value which is output at the central point - of the 4 accumulation timespans. This new point is used for linear - interpolation of the complete timeseries afterwards. - - @Input: - alist: list of size 4, array(2D), type=float - List of 4 timespans as 2-dimensional, horizontal fields. - E.g. [[array_t1], [array_t2], [array_t3], [array_t4]] - - @Return: - nfield: array(2D), type=float - New field which replaces the field at the second position - of the accumulation timespans. - ''' - xa = alist[0] - xb = alist[1] - xc = alist[2] - xd = alist[3] - xa[xa < 0.] = 0. - xb[xb < 0.] = 0. - xc[xc < 0.] = 0. - xd[xd < 0.] = 0. - - xac = 0.5 * xb - mask = xa + xc > 0. - xac[mask] = xb[mask] * xc[mask] / (xa[mask] + xc[mask]) - xbd = 0.5 * xc - mask = xb + xd > 0. - xbd[mask] = xb[mask] * xc[mask] / (xb[mask] + xd[mask]) - nfield = xac + xbd - - return nfield diff --git a/python/pythontest/TestInstallTar/test_untar/python/get_mars_data.py b/python/pythontest/TestInstallTar/test_untar/python/get_mars_data.py deleted file mode 100755 index bf8e02f..0000000 --- a/python/pythontest/TestInstallTar/test_untar/python/get_mars_data.py +++ /dev/null @@ -1,301 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Anne Fouilloux (University of Oslo) -# -# @Date: October 2014 -# -# @Change History: -# -# November 2015 - Leopold Haimberger (University of Vienna): -# - moved the getEIdata program into a function "get_mars_data" -# - moved the AgurmentParser into a seperate function -# - adatpted the function for the use in flex_extract -# - renamed file to get_mars_data -# -# February 2018 - Anne Philipp (University of Vienna): -# - applied PEP8 style guide -# - added structured documentation -# - minor changes in programming style for consistence -# - added function main and moved function calls vom __main__ there -# (necessary for better documentation with docstrings for later -# online documentation) -# - use of UIFiles class for file selection and deletion -# -# -# @License: -# (C) Copyright 2014-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Program Functionality: -# This program can be used as a module in the whole flex_extract process -# or can be run by itself to just extract MARS data from ECMWF. To do so, -# a couple of necessary parameters has to be passed with the program call. -# See documentation for more details. -# -# @Program Content: -# - main -# - get_mars_data -# - do_retrievement -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import os -import sys -import datetime -import inspect -try: - ecapi = True - import ecmwfapi -except ImportError: - ecapi = False - -# software specific classes and modules from flex_extract -from tools import my_error, normal_exit, get_cmdline_arguments, read_ecenv -from EcFlexpart import EcFlexpart -from UioFiles import UioFiles - -# add path to pythonpath so that python finds its buddies -LOCAL_PYTHON_PATH = os.path.dirname(os.path.abspath( - inspect.getfile(inspect.currentframe()))) -if LOCAL_PYTHON_PATH not in sys.path: - sys.path.append(LOCAL_PYTHON_PATH) - -# ------------------------------------------------------------------------------ -# FUNCTION -# ------------------------------------------------------------------------------ -def main(): - ''' - @Description: - If get_mars_data is called from command line, this function controls - the program flow and calls the argumentparser function and - the get_mars_data function for retrieving EC data. - - @Input: - <nothing> - - @Return: - <nothing> - ''' - - args = get_cmdline_arguments() - - try: - c = ControlFile(args.controlfile) - except IOError: - try: - c = ControlFile(LOCAL_PYTHON_PATH + args.controlfile) - except IOError: - print 'Could not read CONTROL file "' + args.controlfile + '"' - print 'Either it does not exist or its syntax is wrong.' - print 'Try "' + sys.argv[0].split('/')[-1] + \ - ' -h" to print usage information' - sys.exit(1) - - env_parameter = read_ecenv(c.ecmwfdatadir + 'python/ECMWF_ENV') - c.assign_args_to_control(args, env_parameter) - c.assign_envs_to_control(env_parameter) - c.check_conditions() - - get_mars_data(c) - normal_exit(c.mailfail, 'Done!') - - return - -def get_mars_data(c): - ''' - @Description: - Retrieves the EC data needed for a FLEXPART simulation. - Start and end dates for retrieval period is set. Retrievals - are divided into smaller periods if necessary and datechunk parameter - is set. - - @Input: - c: instance of class ControlFile - Contains all the parameters of CONTROL file, which are e.g.: - DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, - STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, - LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, - OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, - ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, - MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME - DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - - For more information about format and content of the parameter - see documentation. - - @Return: - <nothing> - ''' - - if not os.path.exists(c.inputdir): - os.makedirs(c.inputdir) - - if c.request == 0 or c.request == 2: - print("Retrieving EC data!") - elif c.request == 1: - print("Printing mars requests!") - - print("start date %s " % (c.start_date)) - print("end date %s " % (c.end_date)) - - if ecapi: - server = ecmwfapi.ECMWFService("mars") - else: - server = False - - c.ecapi = ecapi - print('Using ECMWF WebAPI: ' + str(c.ecapi)) - - # basetime geht rückwärts - - # if basetime 00 - # dann wird von 12 am vortag bis 00 am start tag geholt - # aber ohne 12 selbst sondern 12 + step - - # if basetime 12 - # dann wird von 00 + step bis 12 am start tag geholt - - # purer forecast wird vorwärts bestimmt. - # purer forecast mode ist dann wenn größer 24 stunden - # wie kann das noch festgestellt werden ???? - # nur FC und steps mehr als 24 ? - # die einzige problematik beim reinen forecast ist die benennung der files! - # also sobald es Tagesüberschneidungen gibt - # allerdings ist das relevant und ersichtlich an den NICHT FLUSS DATEN - - - # set start date of retrieval period - start = datetime.date(year=int(c.start_date[:4]), - month=int(c.start_date[4:6]), - day=int(c.start_date[6:])) - startm1 = start - datetime.timedelta(days=1) - - # set end date of retrieval period - end = datetime.date(year=int(c.end_date[:4]), - month=int(c.end_date[4:6]), - day=int(c.end_date[6:])) - - # set time period for one single retrieval - datechunk = datetime.timedelta(days=int(c.date_chunk)) - - if c.basetime == '00': - start = startm1 - - if c.basetime == '00' or c.basetime == '12': - # endp1 = end + datetime.timedelta(days=1) - endp1 = end - else: - # endp1 = end + datetime.timedelta(days=2) - endp1 = end + datetime.timedelta(days=1) - - # -------------- flux data ------------------------------------------------ - if c.request == 0 or c.request == 2: - print('... removing old flux content of ' + c.inputdir) - tobecleaned = UioFiles(c.inputdir, - '*_acc_*.' + str(os.getppid()) + '.*.grb') - tobecleaned.delete_files() - - # if forecast for maximum one day (upto 24h) are to be retrieved, - # collect accumulation data (flux data) - # with additional days in the beginning and at the end - # (used for complete disaggregation of original period) - if c.maxstep <= 24: - do_retrievement(c, server, startm1, endp1, datechunk, fluxes=True) - - # if forecast data longer than 24h are to be retrieved, - # collect accumulation data (flux data) - # with the exact start and end date - # (disaggregation will be done for the - # exact time period with boundary conditions) - else: - do_retrievement(c, server, start, end, datechunk, fluxes=True) - - # -------------- non flux data -------------------------------------------- - if c.request == 0 or c.request == 2: - print('... removing old non flux content of ' + c.inputdir) - tobecleaned = UioFiles(c.inputdir, - '*__*.' + str(os.getppid()) + '.*.grb') - tobecleaned.delete_files() - - do_retrievement(c, server, start, end, datechunk, fluxes=False) - - return - -def do_retrievement(c, server, start, end, delta_t, fluxes=False): - ''' - @Description: - Divides the complete retrieval period in smaller chunks and - retrieves the data from MARS. - - @Input: - c: instance of ControlFile - Contains all the parameters of CONTROL file, which are e.g.: - DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, - STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, - LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, - OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, - ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, - MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME - DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - - For more information about format and content of the parameter - see documentation. - - server: instance of ECMWFService - The server connection to ECMWF - - start: instance of datetime - The start date of the retrieval. - - end: instance of datetime - The end date of the retrieval. - - delta_t: instance of datetime - Delta_t +1 is the maximal time period of a single - retrieval. - - fluxes: boolean, optional - Decides if the flux parameters are to be retrieved or - the rest of the parameter list. - Default value is False. - - @Return: - <nothing> - ''' - - # since actual day also counts as one day, - # we only need to add datechunk - 1 days to retrieval - # for a period - delta_t_m1 = delta_t - datetime.timedelta(days=1) - - day = start - while day <= end: - flexpart = EcFlexpart(c, fluxes) - tmpday = day + delta_t_m1 - if tmpday < end: - dates = day.strftime("%Y%m%d") + "/to/" + \ - tmpday.strftime("%Y%m%d") - else: - dates = day.strftime("%Y%m%d") + "/to/" + \ - end.strftime("%Y%m%d") - - - print("... retrieve " + dates + " in dir " + c.inputdir) - - try: - flexpart.retrieve(server, dates, c.request, c.inputdir) - except IOError: - my_error(c.mailfail, 'MARS request failed') - - day += delta_t - - return - -if __name__ == "__main__": - main() diff --git a/python/pythontest/TestInstallTar/test_untar/python/prepare_flexpart.py b/python/pythontest/TestInstallTar/test_untar/python/prepare_flexpart.py deleted file mode 100755 index 088c2a0..0000000 --- a/python/pythontest/TestInstallTar/test_untar/python/prepare_flexpart.py +++ /dev/null @@ -1,206 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Anne Fouilloux (University of Oslo) -# -# @Date: October 2014 -# -# @Change History: -# -# November 2015 - Leopold Haimberger (University of Vienna): -# - using the WebAPI also for general MARS retrievals -# - job submission on ecgate and cca -# - job templates suitable for twice daily operational dissemination -# - dividing retrievals of longer periods into digestable chunks -# - retrieve also longer term forecasts, not only analyses and -# short term forecast data -# - conversion into GRIB2 -# - conversion into .fp format for faster execution of FLEXPART -# -# February 2018 - Anne Philipp (University of Vienna): -# - applied PEP8 style guide -# - added documentation -# - minor changes in programming style for consistence -# - BUG: removed call of clean_up-Function after call of -# prepareFlexpart in main since it is already called in -# prepareFlexpart at the end! -# - created function main and moved the two function calls for -# arguments and prepare_flexpart into it -# -# @License: -# (C) Copyright 2014-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Program Functionality: -# This program prepares the final version of the grib files which are -# then used by FLEXPART. It converts the bunch of grib files extracted -# via get_mars_data by doing for example the necessary conversion to get -# consistent grids or the disaggregation of flux data. Finally, the -# program combines the data fields in files per available hour with the -# naming convention xxYYMMDDHH, where xx should be 2 arbitrary letters -# (mostly xx is chosen to be "EN"). -# -# @Program Content: -# - main -# - prepare_flexpart -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import datetime -import os -import inspect -import sys -import socket -import _config - -# software specific classes and modules from flex_extract -from UioFiles import UioFiles -from tools import clean_up, get_cmdline_arguments, read_ecenv -from EcFlexpart import EcFlexpart - -ecapi = 'ecmwf' not in socket.gethostname() -try: - if ecapi: - import ecmwfapi -except ImportError: - ecapi = False - -# add path to pythonpath so that python finds its buddies -LOCAL_PYTHON_PATH = os.path.dirname(os.path.abspath( - inspect.getfile(inspect.currentframe()))) -if LOCAL_PYTHON_PATH not in sys.path: - sys.path.append(LOCAL_PYTHON_PATH) - - -# ------------------------------------------------------------------------------ -# FUNCTION -# ------------------------------------------------------------------------------ -def main(): - ''' - @Description: - If prepare_flexpart is called from command line, this function controls - the program flow and calls the argumentparser function and - the prepare_flexpart function for preparation of GRIB data for FLEXPART. - - @Input: - <nothing> - - @Return: - <nothing> - ''' - - args = get_cmdline_arguments() - - try: - c = ControlFile(args.controlfile) - except IOError: - try: - c = ControlFile(LOCAL_PYTHON_PATH + args.controlfile) - except IOError: - print 'Could not read CONTROL file "' + args.controlfile + '"' - print 'Either it does not exist or its syntax is wrong.' - print 'Try "' + sys.argv[0].split('/')[-1] + \ - ' -h" to print usage information' - sys.exit(1) - - env_parameter = read_ecenv(c.ecmwfdatadir + 'python/ECMWF_ENV') - c.assign_args_to_control(args, env_parameter) - c.assign_envs_to_control(env_parameter) - c.check_conditions() - prepare_flexpart(args.ppid, c) - - return - -def prepare_flexpart(ppid, c): - ''' - @Description: - Lists all grib files retrieved from MARS with get_mars_data and - uses prepares data for the use in FLEXPART. Specific data fields - are converted to a different grid and the flux data are going to be - disaggregated. The data fields are collected by hour and stored in - a file with a specific FLEXPART relevant naming convention. - - @Input: - ppid: int - Contains the ppid number of the current ECMWF job. If it is called - from this script, it is "None". - - c: instance of class ControlFile - Contains all the parameters of CONTROL file, which are e.g.: - DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, - STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, - LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, - OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, - ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, - MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME - DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - - For more information about format and content of the parameter - see documentation. - - @Return: - <nothing> - ''' - - if not ppid: - c.ppid = str(os.getppid()) - else: - c.ppid = ppid - - c.ecapi = ecapi - - # create the start and end date - start = datetime.date(year=int(c.start_date[:4]), - month=int(c.start_date[4:6]), - day=int(c.start_date[6:])) - - end = datetime.date(year=int(c.end_date[:4]), - month=int(c.end_date[4:6]), - day=int(c.end_date[6:])) - - # assign starting date minus 1 day - # since for basetime 00 we need the 12 hours upfront - # (the day before from 12 UTC to current day 00 UTC) - if c.basetime == '00': - start = start - datetime.timedelta(days=1) - - print 'Prepare ' + start.strftime("%Y%m%d") + \ - "/to/" + end.strftime("%Y%m%d") - - # create output dir if necessary - if not os.path.exists(c.outputdir): - os.makedirs(c.outputdir) - - # get all files with flux data to be deaccumulated - inputfiles = UioFiles(c.inputdir, '*OG_acc_SL*.' + c.ppid + '.*') - - # deaccumulate the flux data - flexpart = EcFlexpart(c, fluxes=True) - flexpart.write_namelist(c, 'fort.4') - flexpart.deacc_fluxes(inputfiles, c) - - # get a list of all files from the root inputdir - inputfiles = UioFiles(c.inputdir, '????__??.*' + c.ppid + '.*') - - # produce FLEXPART-ready GRIB files and process them - - # copy/transfer/interpolate them or make them GRIB2 - flexpart = EcFlexpart(c, fluxes=False) - flexpart.create(inputfiles, c) - flexpart.process_output(c) - - # check if in debugging mode, then store all files - # otherwise delete temporary files - if int(c.debug) != 0: - print '\nTemporary files left intact' - else: - clean_up(c) - - return - -if __name__ == "__main__": - main() diff --git a/python/pythontest/TestInstallTar/test_untar/python/profiling.py b/python/pythontest/TestInstallTar/test_untar/python/profiling.py deleted file mode 100644 index 4511af2..0000000 --- a/python/pythontest/TestInstallTar/test_untar/python/profiling.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#************************************************************************ -# ToDo AP -# - check license of book content -#************************************************************************ -#******************************************************************************* -# -# @Author: Anne Philipp (University of Vienna) -# -# @Date: March 2018 -# -# @License: -# (C) Copyright 2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Program functionality: -# This module is not part of flex_extract. It is just used for testing and -# performance analysis of some functions. -# -# @Program Content: -# - timefn -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -from functools import wraps -import time - -# ------------------------------------------------------------------------------ -# FUNCTION -# ------------------------------------------------------------------------------ -def timefn(fn): - ''' - @Description: - Decorator function. It takes the inner function as an argument. - ''' - @wraps(fn) - def measure_time(*args, **kwargs): - ''' - @Descripton: - Passes the arguments through fn for execution. Around the - execution of fn the time is captured to execute the fn function - and prints the result along with the function name. - - This is taken from the book "High Performance Python" from - Micha Gorelick and Ian Ozsvald, O'Reilly publisher, 2014, - ISBN: 978-1-449-36159-4 - - @Input: - *args: undefined - A variable number of positional arguments. - - **kwargs: undefined - A variable number of key/value arguments. - - @Return: - <nothing> - ''' - - t1 = time.time() - result = fn(*args, **kwargs) - t2 = time.time() - print "@timefn:" + fn.func_name + " took " + str(t2 - t1) + " seconds" - - return result - - return measure_time diff --git a/python/pythontest/TestInstallTar/test_untar/python/submit.py b/python/pythontest/TestInstallTar/test_untar/python/submit.py deleted file mode 100755 index 967ed94..0000000 --- a/python/pythontest/TestInstallTar/test_untar/python/submit.py +++ /dev/null @@ -1,200 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Anne Fouilloux (University of Oslo) -# -# @Date: October 2014 -# -# @Change History: -# -# November 2015 - Leopold Haimberger (University of Vienna): -# - job submission on ecgate and cca -# - job templates suitable for twice daily operational dissemination -# -# February 2018 - Anne Philipp (University of Vienna): -# - applied PEP8 style guide -# - added documentation -# - minor changes in programming style (for consistence) -# -# @License: -# (C) Copyright 2014-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Program Functionality: -# This program is the main program of flex_extract and controls the -# program flow. -# If it is supposed to work locally then it works through the necessary -# functions get_mars_data and prepareFlexpart. Otherwise it prepares -# a shell job script which will do the necessary work on the -# ECMWF server and is submitted via ecaccess-job-submit. -# -# @Program Content: -# - main -# - submit -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import os -import sys -import subprocess -import inspect -import collections - -# software specific classes and modules from flex_extract -import _config -from tools import normal_exit, get_cmdline_arguments, submit_job_to_ecserver, \ - read_ecenv -from get_mars_data import get_mars_data -from prepare_flexpart import prepare_flexpart -from ControlFile import ControlFile - -# ------------------------------------------------------------------------------ -# FUNCTIONS -# ------------------------------------------------------------------------------ - -def main(): - ''' - @Description: - Get the arguments from script call and from CONTROL file. - Decides from the argument "queue" if the local version - is done "queue=None" or the gateway version with "queue=ecgate" - or "queue=cca". - - @Input: - <nothing> - - @Return: - <nothing> - ''' - - called_from_dir = os.getcwd() - - args = get_cmdline_arguments() - - try: - c = ControlFile(args.controlfile) - except IOError: - try: - c = ControlFile(_config.PATH_LOCAL_PYTHON + args.controlfile) - except IOError: - print 'Could not read CONTROL file "' + args.controlfile + '"' - print 'Either it does not exist or its syntax is wrong.' - print 'Try "' + sys.argv[0].split('/')[-1] + \ - ' -h" to print usage information' - sys.exit(1) - - env_parameter = read_ecenv(c.ecmwfdatadir + 'python/ECMWF_ENV') - c.assign_args_to_control(args) - c.assign_envs_to_control(env_parameter) - c.check_conditions() - - # on local side - # on ECMWF server this would also be the local side - if args.queue is None: - if c.inputdir[0] != '/': - c.inputdir = os.path.join(called_from_dir, c.inputdir) - if c.outputdir[0] != '/': - c.outputdir = os.path.join(called_from_dir, c.outputdir) - get_mars_data(c) - if c.request == 0 or c.request == 2: - prepare_flexpart(args.ppid, c) - normal_exit(c.mailfail, 'FLEX_EXTRACT IS DONE!') - else: - normal_exit(c.mailfail, 'PRINTING MARS_REQUESTS DONE!') - # on ECMWF server - else: - submit(args.job_template, c, args.queue) - - return - -def submit(jtemplate, c, queue): - ''' - @Description: - Prepares the job script and submit it to the specified queue. - - @Input: - jtemplate: string - Job template file for submission to ECMWF. It contains all necessary - module and variable settings for the ECMWF environment as well as - the job call and mail report instructions. - Default is "job.temp". - - c: instance of class ControlFile - Contains all the parameters of CONTROL file, which are e.g.: - DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, - STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, - LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, - OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, - ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, - MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME - DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - - For more information about format and content of the parameter - see documentation. - - queue: string - Name of queue for submission to ECMWF (e.g. ecgate or cca ) - - @Return: - <nothing> - ''' - - # read template file and get index for CONTROL input - with open(jtemplate) as f: - lftext = f.read().split('\n') - insert_point = lftext.index('EOF') - - if not c.basetime: - # --------- create on demand job script ------------------------------------ - if c.maxstep > 24: - print '---- Pure forecast mode! ----' - else: - print '---- On-demand mode! ----' - job_file = jtemplate[:-4] + 'ksh' - clist = c.to_list() - - lftextondemand = lftext[:insert_point] + clist + lftext[insert_point:] - - with open(job_file, 'w') as f: - f.write('\n'.join(lftextondemand)) - - result_code = submit_job_to_ecserver(queue, job_file) - - else: - # --------- create operational job script ---------------------------------- - print '---- Operational mode! ----' - job_file = jtemplate[:-5] + 'oper.ksh' - #colist = [] - - if c.maxstep: - mt = int(c.maxstep) - else: - mt = 0 - - c.start_date = '${MSJ_YEAR}${MSJ_MONTH}${MSJ_DAY}' - c.end_date = '${MSJ_YEAR}${MSJ_MONTH}${MSJ_DAY}' - c.base_time = '${MSJ_BASETIME}' - if mt > 24: - c.time = '${MSJ_BASETIME} {MSJ_BASETIME}' - - colist = c.to_list() - - lftextoper = lftext[:insert_point] + colist + lftext[insert_point + 2:] - - with open(job_file, 'w') as f: - f.write('\n'.join(lftextoper)) - - result_code = submit_job_to_ecserver(queue, job_file) - - # -------------------------------------------------------------------------- - print 'You should get an email with subject flex.hostname.pid' - - return - -if __name__ == "__main__": - main() diff --git a/python/pythontest/TestInstallTar/test_untar/python/test_suite.py b/python/pythontest/TestInstallTar/test_untar/python/test_suite.py deleted file mode 100755 index 6cd9ed7..0000000 --- a/python/pythontest/TestInstallTar/test_untar/python/test_suite.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Leopold Haimberger (University of Vienna) -# -# @Date: December 2015 -# -# @Change History: -# -# February 2018 - Anne Philipp (University of Vienna): -# - applied PEP8 style guide -# - added documentation -# -# @License: -# (C) Copyright 2015-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Program Functionality: -# This script triggers the flex_extract test suite. Call with -# test_suite.py [test group] -# -# @Program Content: -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import os -import sys -import json -import subprocess - -# ------------------------------------------------------------------------------ -# PROGRAM -# ------------------------------------------------------------------------------ -try: - taskfile = open('test_suite.json') -except IOError: - print 'could not open suite definition file test_suite.json' - exit() - -if not os.path.isfile('../src/CONVERT2'): - print '../src/CONVERT2 could not be found' - print 'please run "install.py --target=local" first' - exit() - -fprs = os.getenv('FLEXPART_ROOT_SCRIPTS') -if fprs is None: - print 'FLEXPART_ROOT_SCRIPTS not set .. some test jobs may fail' - -tasks = json.load(taskfile, encoding='latin-1') -taskfile.close() -if not os.path.exists('../test'): - os.makedirs('../test') -if len(sys.argv) > 1: - groups = sys.argv[1:] -else: - groups = ['xinstall', 'default', 'ops', 'work', 'cv', 'fc']#,'hires'] -jobcounter = 0 -jobfailed = 0 -for g in groups: - try: - tk, tv = g, tasks[g] - finally: - pass - garglist = [] - for ttk, ttv in tv.iteritems(): - if isinstance(ttv, basestring): - if ttk != 'script': - garglist.append('--' + ttk) - if ttv[0] == '$': - garglist.append(os.path.expandvars(ttv)) - else: - garglist.append(ttv) - for ttk, ttv in tv.iteritems(): - if isinstance(ttv, dict): - arglist = [] - for tttk, tttv in ttv.iteritems(): - if isinstance(tttv, basestring): - arglist.append('--' + tttk) - if '$' in tttv[0]: - arglist.append(os.path.expandvars(tttv)) - else: - arglist.append(tttv) - print 'Command: ', ' '.join([tv['script']] + garglist + arglist) - o = '../test/' + tk + '_' + ttk + '_' + '_'.join(ttv.keys()) - print 'Output will be sent to ', o - f = open(o, 'w') - try: - p = subprocess.check_call([tv['script']] + garglist + arglist, - stdout=f, stderr=f) - except subprocess.CalledProcessError as e: - f.write('\nFAILED\n') - print 'FAILED' - jobfailed += 1 - jobcounter += 1 - f.close() - -print 'Test suite tasks completed' -print str(jobcounter-jobfailed) + ' successful, ' + str(jobfailed) + ' failed' -print 'If tasks have been submitted via ECACCESS please check emails' diff --git a/python/pythontest/TestInstallTar/test_untar/python/tools.py b/python/pythontest/TestInstallTar/test_untar/python/tools.py deleted file mode 100644 index 8e1e405..0000000 --- a/python/pythontest/TestInstallTar/test_untar/python/tools.py +++ /dev/null @@ -1,531 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Anne Philipp (University of Vienna) -# -# @Date: May 2018 -# -# @Change History: -# October 2014 - Anne Fouilloux (University of Oslo) -# - created functions silent_remove and product (taken from ECMWF) -# -# November 2015 - Leopold Haimberger (University of Vienna) -# - created functions: interpret_args_and_control, clean_up -# my_error, normal_exit, init128, to_param_id -# -# April 2018 - Anne Philipp (University of Vienna): -# - applied PEP8 style guide -# - added documentation -# - moved all functions from file Flexparttools to this file tools -# - added function get_list_as_string -# - seperated args and control interpretation -# -# @License: -# (C) Copyright 2014-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Modul Description: -# This module contains a couple of helpful functions which are -# used in different places in flex_extract. -# -# @Module Content: -# - get_cmdline_arguments -# - clean_up -# - my_error -# - normal_exit -# - product -# - silent_remove -# - init128 -# - to_param_id -# - get_list_as_string -# - make_dir -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import os -import errno -import sys -import glob -import subprocess -import traceback -from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter - -# ------------------------------------------------------------------------------ -# FUNCTIONS -# ------------------------------------------------------------------------------ - -def get_cmdline_arguments(): - ''' - @Description: - Decomposes the command line arguments and assigns them to variables. - Apply default values for non mentioned arguments. - - @Input: - <nothing> - - @Return: - args: instance of ArgumentParser - Contains the commandline arguments from script/program call. - ''' - - parser = ArgumentParser(description='Retrieve FLEXPART input from \ - ECMWF MARS archive', - formatter_class=ArgumentDefaultsHelpFormatter) - - # the most important arguments - parser.add_argument("--start_date", dest="start_date", default=None, - help="start date YYYYMMDD") - parser.add_argument("--end_date", dest="end_date", default=None, - help="end_date YYYYMMDD") - parser.add_argument("--date_chunk", dest="date_chunk", default=None, - help="# of days to be retrieved at once") - - # some arguments that override the default in the CONTROL file - parser.add_argument("--basetime", dest="basetime", default=None, - help="base such as 00/12 (for half day retrievals)") - parser.add_argument("--step", dest="step", default=None, - help="steps such as 00/to/48") - parser.add_argument("--levelist", dest="levelist", default=None, - help="Vertical levels to be retrieved, e.g. 30/to/60") - parser.add_argument("--area", dest="area", default=None, - help="area defined as north/west/south/east") - - # set the working directories - parser.add_argument("--inputdir", dest="inputdir", default=None, - help="root directory for storing intermediate files") - parser.add_argument("--outputdir", dest="outputdir", default=None, - help="root directory for storing output files") - parser.add_argument("--flexpart_root_scripts", dest="flexpart_root_scripts", - default=None, - help="FLEXPART root directory (to find grib2flexpart \ - and COMMAND file)\n Normally flex_extract resides in \ - the scripts directory of the FLEXPART distribution") - - # this is only used by prepare_flexpart.py to rerun a postprocessing step - parser.add_argument("--ppid", dest="ppid", default=None, - help="specify parent process id for \ - rerun of prepare_flexpart") - - # arguments for job submission to ECMWF, only needed by submit.py - parser.add_argument("--job_template", dest='job_template', - default="job.temp", - help="job template file for submission to ECMWF") - parser.add_argument("--queue", dest="queue", default=None, - help="queue for submission to ECMWF \ - (e.g. ecgate or cca )") - parser.add_argument("--controlfile", dest="controlfile", - default='CONTROL.temp', - help="file with CONTROL parameters") - parser.add_argument("--debug", dest="debug", default=None, - help="debug mode - leave temporary files intact") - parser.add_argument("--request", dest="request", default=None, - help="list all mars request in file mars_requests.dat \ - and skip submission to mars") - - args = parser.parse_args() - - return args - -def read_ecenv(filename): - ''' - @Description: - Reads the file into a dictionary where the key values are the parameter - names. - - @Input: - filename: string - Name of file where the ECMWV environment parameters are stored. - - @Return: - envs: dict - ''' - envs= {} - print filename - with open(filename, 'r') as f: - for line in f: - data = line.strip().split() - envs[str(data[0])] = str(data[1]) - - return envs - -def clean_up(c): - ''' - @Description: - Remove all files from intermediate directory - (inputdir from CONTROL file). - - @Input: - c: instance of class ControlFile - Contains all the parameters of CONTROL file, which are e.g.: - DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, - STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, - LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, - OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, - ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, - MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME - DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS - - For more information about format and content of the parameter - see documentation. - - @Return: - <nothing> - ''' - - print "clean_up" - - cleanlist = glob.glob(c.inputdir + "/*") - for clist in cleanlist: - if c.prefix not in clist: - silent_remove(clist) - if c.ecapi is False and (c.ectrans == '1' or c.ecstorage == '1'): - silent_remove(clist) - - print "Done" - - return - - -def my_error(users, message='ERROR'): - ''' - @Description: - Prints a specified error message which can be passed to the function - before exiting the program. - - @Input: - user: list of strings - Contains all email addresses which should be notified. - It might also contain just the ecmwf user name which wil trigger - mailing to the associated email address for this user. - - message: string, optional - Error message. Default value is "ERROR". - - @Return: - <nothing> - ''' - - print message - - # comment if user does not want email notification directly from python - for user in users: - if '${USER}' in user: - user = os.getenv('USER') - try: - p = subprocess.Popen(['mail', '-s flex_extract_v7.1 ERROR', - os.path.expandvars(user)], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - bufsize=1) - trace = '\n'.join(traceback.format_stack()) - pout = p.communicate(input=message + '\n\n' + trace)[0] - except ValueError as e: - print 'ERROR: ', e - sys.exit('Email could not be sent!') - else: - print 'Email sent to ' + os.path.expandvars(user) + ' ' + \ - pout.decode() - - sys.exit(1) - - return - - -def normal_exit(users, message='Done!'): - ''' - @Description: - Prints a specific exit message which can be passed to the function. - - @Input: - user: list of strings - Contains all email addresses which should be notified. - It might also contain just the ecmwf user name which wil trigger - mailing to the associated email address for this user. - - message: string, optional - Message for exiting program. Default value is "Done!". - - @Return: - <nothing> - - ''' - print message - - # comment if user does not want notification directly from python - for user in users: - if '${USER}' in user: - user = os.getenv('USER') - try: - p = subprocess.Popen(['mail', '-s flex_extract_v7.1 normal exit', - os.path.expandvars(user)], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - bufsize=1) - pout = p.communicate(input=message+'\n\n')[0] - except ValueError as e: - print 'ERROR: ', e - print 'Email could not be sent!' - else: - print 'Email sent to ' + os.path.expandvars(user) + ' ' + \ - pout.decode() - - return - - -def product(*args, **kwds): - ''' - @Description: - This method is taken from an example at the ECMWF wiki website. - https://software.ecmwf.int/wiki/display/GRIB/index.py; 2018-03-16 - - This method combines the single characters of the passed arguments - with each other. So that each character of each argument value - will be combined with each character of the other arguments as a tuple. - - Example: - product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy - product(range(2), repeat = 3) --> 000 001 010 011 100 101 110 111 - - @Input: - *args: tuple - Positional arguments (arbitrary number). - - **kwds: dictionary - Contains all the keyword arguments from *args. - - @Return: - prod: tuple - Return will be done with "yield". A tuple of combined arguments. - See example in description above. - ''' - pools = map(tuple, args) * kwds.get('repeat', 1) - result = [[]] - for pool in pools: - result = [x + [y] for x in result for y in pool] - for prod in result: - yield tuple(prod) - - return - - -def silent_remove(filename): - ''' - @Description: - Remove file if it exists. - The function does not fail if the file does not exist. - - @Input: - filename: string - The name of the file to be removed without notification. - - @Return: - <nothing> - ''' - try: - os.remove(filename) - except OSError as e: - if e.errno != errno.ENOENT: - # errno.ENOENT = no such file or directory - raise # re-raise exception if a different error occured - - return - - -def init128(filepath): - ''' - @Description: - Opens and reads the grib file with table 128 information. - - @Input: - filepath: string - Path to file of ECMWF grib table number 128. - - @Return: - table128: dictionary - Contains the ECMWF grib table 128 information. - The key is the parameter number and the value is the - short name of the parameter. - ''' - table128 = dict() - with open(filepath) as f: - fdata = f.read().split('\n') - for data in fdata: - if data[0] != '!': - table128[data[0:3]] = data[59:64].strip() - - return table128 - - -def to_param_id(pars, table): - ''' - @Description: - Transform parameter names to parameter ids - with ECMWF grib table 128. - - @Input: - pars: string - Addpar argument from CONTROL file in the format of - parameter names instead of ids. The parameter short - names are sepearted with "/" and they are passed as - one single string. - - table: dictionary - Contains the ECMWF grib table 128 information. - The key is the parameter number and the value is the - short name of the parameter. - - @Return: - ipar: list of integer - List of addpar parameters from CONTROL file transformed to - parameter ids in the format of integer. - ''' - cpar = pars.upper().split('/') - ipar = [] - for par in cpar: - for k, v in table.iteritems(): - if par == k or par == v: - ipar.append(int(k)) - break - else: - print 'Warning: par ' + par + ' not found in table 128' - - return ipar - -def get_list_as_string(list_obj, concatenate_sign=', '): - ''' - @Description: - Converts a list of arbitrary content into a single string. - - @Input: - list_obj: list - A list with arbitrary content. - - concatenate_sign: string, optional - A string which is used to concatenate the single - list elements. Default value is ", ". - - @Return: - str_of_list: string - The content of the list as a single string. - ''' - - str_of_list = concatenate_sign.join(str(l) for l in list_obj) - - return str_of_list - -def make_dir(directory): - ''' - @Description: - Creates a directory and gives a warning if the directory - already exists. The program stops only if there is another problem. - - @Input: - directory: string - The directory name including the path which should be created. - - @Return: - <nothing> - ''' - try: - os.makedirs(directory) - except OSError as e: - if e.errno != errno.EEXIST: - # errno.EEXIST = directory already exists - raise # re-raise exception if a different error occured - else: - print 'WARNING: Directory {0} already exists!'.format(directory) - - return - -def put_file_to_ecserver(ecd, filename, target, ecuid, ecgid): - ''' - @Description: - Uses the ecaccess-file-put command to send a file to the ECMWF servers. - - NOTE: - The return value is just for testing reasons. It does not have - to be used from the calling function since the whole error handling - is done in here. - - @Input: - ecd: string - The path were the file is stored. - - filename: string - The name of the file to send to the ECMWF server. - - target: string - The target queue where the file should be sent to. - - ecuid: string - The user id on ECMWF server. - - ecgid: string - The group id on ECMWF server. - - @Return: - rcode: string - Resulting code of command execution. If successful the string - will be empty. - ''' - - try: - rcode = subprocess.check_output(['ecaccess-file-put', - ecd + '/' + filename, - target + ':/home/ms/' + - ecgid + '/' + ecuid + - '/' + filename], - stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - print('... ERROR CODE:\n ... ' + str(e.returncode)) - print('... ERROR MESSAGE:\n ... ' + str(e)) - - print('\n... Do you have a valid ecaccess certification key?') - sys.exit('... ECACCESS-FILE-PUT FAILED!') - - return rcode - -def submit_job_to_ecserver(target, jobname): - ''' - @Description: - Uses ecaccess-job-submit command to submit a job to the ECMWF server. - - NOTE: - The return value is just for testing reasons. It does not have - to be used from the calling function since the whole error handling - is done in here. - - @Input: - target: string - The target where the file should be sent to, e.g. the queue. - - jobname: string - The name of the jobfile to be submitted to the ECMWF server. - - @Return: - rcode: string - Resulting code of command execution. If successful the string - will contain an integer number, representing the id of the job - at the ecmwf server. - ''' - - try: - rcode = subprocess.check_output(['ecaccess-job-submit', - '-queueName', target, - jobname]) - except subprocess.CalledProcessError as e: - print('... ERROR CODE:\n ... ' + str(e.returncode)) - print('... ERROR MESSAGE:\n ... ' + str(e)) - - - print('\n... Do you have a valid ecaccess certification key?') - sys.exit('... ECACCESS-JOB-SUBMIT FAILED!') - - return rcode diff --git a/python/pythontest/TestUIOFiles.py b/python/pythontest/TestUIOFiles.py deleted file mode 100644 index d60cbf0..0000000 --- a/python/pythontest/TestUIOFiles.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import unittest -import os -import sys -sys.path.append('../python') -import UioFiles - - -class TestUioFiles(unittest.TestCase): - ''' - Test class to test the UIOFiles methods. - ''' - - def setUp(self): - ''' - @Description: - Prepare test case. Initialize comparing filelist and - the test path. - - @Input: - self: instance of TestUIOFiles - Class to test the UIOFiles methods. - - @Return: - <nothing> - ''' - self.testpath = os.path.join(os.path.dirname(__file__), 'TestDir') - self.expected = ['FCGG__SL.20160410.40429.16424.grb', - 'FCOG__ML.20160410.40429.16424.grb', - 'FCSH__ML.20160410.40429.16424.grb', - 'OG_OROLSM__SL.20160410.40429.16424.grb', - 'FCOG_acc_SL.20160409.40429.16424.grb', - 'FCOG__SL.20160410.40429.16424.grb', - 'FCSH__SL.20160410.40429.16424.grb'] - - return - - def test_listFiles(self): - ''' - @Description: - Test the listFiles method from class UIOFiles. - - @Input: - self: instance of TestClass - Class to test the UIOFiles methods. - - @Return: - <nothing> - ''' - - # Initialise and collect filenames - files = UioFiles.UioFiles(['.grb']) - files.list_files(self.testpath, '*') - # get the basename to just check for equality of filenames - filelist = [os.path.basename(f) for f in files.files] - # comparison of expected filenames against the collected ones - self.assertItemsEqual(self.expected, filelist) - - return - -if __name__ == "__main__": - unittest.main() \ No newline at end of file diff --git a/python/pythontest/testecmwfapi.py b/python/pythontest/testecmwfapi.py deleted file mode 100644 index 90e49ee..0000000 --- a/python/pythontest/testecmwfapi.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python -from ecmwfapi import ECMWFDataServer - -server = ECMWFDataServer() - -server.retrieve({ - 'dataset' : "interim", - 'time' : "00", - 'date' : "2013-09-01/to/2013-09-30", - 'step' : "0", - 'type' : "an", - 'levtype' : "sfc", - 'param' : "165.128/41.128", - 'grid' : "0.75/0.75", - 'target' : "interim201309.grib" -}) diff --git a/python/test_suite.py b/python/test_suite.py deleted file mode 100755 index 6cd9ed7..0000000 --- a/python/test_suite.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -#******************************************************************************* -# @Author: Leopold Haimberger (University of Vienna) -# -# @Date: December 2015 -# -# @Change History: -# -# February 2018 - Anne Philipp (University of Vienna): -# - applied PEP8 style guide -# - added documentation -# -# @License: -# (C) Copyright 2015-2018. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# -# @Program Functionality: -# This script triggers the flex_extract test suite. Call with -# test_suite.py [test group] -# -# @Program Content: -# -#******************************************************************************* - -# ------------------------------------------------------------------------------ -# MODULES -# ------------------------------------------------------------------------------ -import os -import sys -import json -import subprocess - -# ------------------------------------------------------------------------------ -# PROGRAM -# ------------------------------------------------------------------------------ -try: - taskfile = open('test_suite.json') -except IOError: - print 'could not open suite definition file test_suite.json' - exit() - -if not os.path.isfile('../src/CONVERT2'): - print '../src/CONVERT2 could not be found' - print 'please run "install.py --target=local" first' - exit() - -fprs = os.getenv('FLEXPART_ROOT_SCRIPTS') -if fprs is None: - print 'FLEXPART_ROOT_SCRIPTS not set .. some test jobs may fail' - -tasks = json.load(taskfile, encoding='latin-1') -taskfile.close() -if not os.path.exists('../test'): - os.makedirs('../test') -if len(sys.argv) > 1: - groups = sys.argv[1:] -else: - groups = ['xinstall', 'default', 'ops', 'work', 'cv', 'fc']#,'hires'] -jobcounter = 0 -jobfailed = 0 -for g in groups: - try: - tk, tv = g, tasks[g] - finally: - pass - garglist = [] - for ttk, ttv in tv.iteritems(): - if isinstance(ttv, basestring): - if ttk != 'script': - garglist.append('--' + ttk) - if ttv[0] == '$': - garglist.append(os.path.expandvars(ttv)) - else: - garglist.append(ttv) - for ttk, ttv in tv.iteritems(): - if isinstance(ttv, dict): - arglist = [] - for tttk, tttv in ttv.iteritems(): - if isinstance(tttv, basestring): - arglist.append('--' + tttk) - if '$' in tttv[0]: - arglist.append(os.path.expandvars(tttv)) - else: - arglist.append(tttv) - print 'Command: ', ' '.join([tv['script']] + garglist + arglist) - o = '../test/' + tk + '_' + ttk + '_' + '_'.join(ttv.keys()) - print 'Output will be sent to ', o - f = open(o, 'w') - try: - p = subprocess.check_call([tv['script']] + garglist + arglist, - stdout=f, stderr=f) - except subprocess.CalledProcessError as e: - f.write('\nFAILED\n') - print 'FAILED' - jobfailed += 1 - jobcounter += 1 - f.close() - -print 'Test suite tasks completed' -print str(jobcounter-jobfailed) + ' successful, ' + str(jobfailed) + ' failed' -print 'If tasks have been submitted via ECACCESS please check emails' diff --git a/run/jobscripts/job.ksh b/run/jobscripts/job.ksh index c77cc78..b659d5a 100644 --- a/run/jobscripts/job.ksh +++ b/run/jobscripts/job.ksh @@ -96,7 +96,7 @@ omegadiff 0 outputdir ../work prefix EItest_ queue ecgate -request 0 +request 1 resol 63 right 10000 smooth 0 diff --git a/run/mars_requests.dat b/run/mars_requests.dat deleted file mode 100644 index 12a9af3..0000000 --- a/run/mars_requests.dat +++ /dev/null @@ -1,252 +0,0 @@ -mars -gaussian: -stream: OPER -levelist: 1 -area: 40.0/-10.0/30.0/10.0 -marsclass: EI -levtype: SFC -number: OFF -expver: 1 -repres: -target: /raid60/nas/tmc/Anne/Interpolation/flexextract/flex_extract_v7.1/python/../work/FCOG_acc_SL.20170808.41511.90849.grb -step: 3/to/12/by/3 -grid: 5.0/5.0 -param: LSP/CP/SSHF/EWSS/NSSS/SSR -time: 00/12 -date: 20170808/to/20170810 -resol: 63 -type: FC -accuracy: 24 - - -mars -gaussian: -stream: OPER -levelist: 59/to/60 -area: 40.0/-10.0/30.0/10.0 -marsclass: EI -levtype: ML -number: OFF -expver: 1 -repres: -target: /raid60/nas/tmc/Anne/Interpolation/flexextract/flex_extract_v7.1/python/../work/FCOG__ML.20170809.41511.90849.grb -step: 03/09 -grid: 5.0/5.0 -param: T/Q -time: 00/12 -date: 20170809/to/20170809 -resol: 63 -type: FC -accuracy: 24 - - -mars -gaussian: -stream: OPER -levelist: 1 -area: 40.0/-10.0/30.0/10.0 -marsclass: EI -levtype: SFC -number: OFF -expver: 1 -repres: -target: /raid60/nas/tmc/Anne/Interpolation/flexextract/flex_extract_v7.1/python/../work/OG_OROLSM__SL.20170809.41511.90849.grb -step: 000 -grid: 5.0/5.0 -param: 160/27/28/173 -time: 00 -date: 20170809 -resol: 63 -type: AN -accuracy: 24 - - -mars -gaussian: reduced -stream: OPER -levelist: 1 -area: -marsclass: EI -levtype: ML -number: OFF -expver: 1 -repres: -target: /raid60/nas/tmc/Anne/Interpolation/flexextract/flex_extract_v7.1/python/../work/FCGG__SL.20170809.41511.90849.grb -step: 03/09 -grid: 32 -param: Q -time: 00/12 -date: 20170809/to/20170809 -resol: 63 -type: FC -accuracy: 24 - - -mars -gaussian: -stream: OPER -levelist: 1/to/60 -area: 40.0/-10.0/30.0/10.0 -marsclass: EI -levtype: ML -number: OFF -expver: 1 -repres: -target: /raid60/nas/tmc/Anne/Interpolation/flexextract/flex_extract_v7.1/python/../work/FCGG__ML.20170809.41511.90849.grb -step: 03/09 -grid: 32 -param: U/V/D/77 -time: 00/12 -date: 20170809/to/20170809 -resol: 63 -type: FC -accuracy: 24 - - -mars -gaussian: -stream: OPER -levelist: 1 -area: 40.0/-10.0/30.0/10.0 -marsclass: EI -levtype: ML -number: OFF -expver: 1 -repres: -target: /raid60/nas/tmc/Anne/Interpolation/flexextract/flex_extract_v7.1/python/../work/FCSH__SL.20170809.41511.90849.grb -step: 03/09 -grid: OFF -param: LNSP -time: 00/12 -date: 20170809/to/20170809 -resol: 63 -type: FC -accuracy: 24 - - -mars -gaussian: -stream: OPER -levelist: 1 -area: 40.0/-10.0/30.0/10.0 -marsclass: EI -levtype: SFC -number: OFF -expver: 1 -repres: -target: /raid60/nas/tmc/Anne/Interpolation/flexextract/flex_extract_v7.1/python/../work/FCOG__SL.20170809.41511.90849.grb -step: 03/09 -grid: 5.0/5.0 -param: 141/151/164/165/166/167/168/129/172/186/187/188/235/139/39 -time: 00/12 -date: 20170809/to/20170809 -resol: 63 -type: FC -accuracy: 24 - - -mars -gaussian: -stream: OPER -levelist: 59/to/60 -area: 40.0/-10.0/30.0/10.0 -marsclass: EI -levtype: ML -number: OFF -expver: 1 -repres: -target: /raid60/nas/tmc/Anne/Interpolation/flexextract/flex_extract_v7.1/python/../work/ANOG__ML.20170809.41511.90849.grb -step: 00 -grid: 5.0/5.0 -param: T/Q -time: 00/06/12/18 -date: 20170809/to/20170809 -resol: 63 -type: AN -accuracy: 24 - - -mars -gaussian: reduced -stream: OPER -levelist: 1 -area: -marsclass: EI -levtype: ML -number: OFF -expver: 1 -repres: -target: /raid60/nas/tmc/Anne/Interpolation/flexextract/flex_extract_v7.1/python/../work/ANGG__SL.20170809.41511.90849.grb -step: 00 -grid: 32 -param: Q -time: 00/06/12/18 -date: 20170809/to/20170809 -resol: 63 -type: AN -accuracy: 24 - - -mars -gaussian: -stream: OPER -levelist: 1/to/60 -area: 40.0/-10.0/30.0/10.0 -marsclass: EI -levtype: ML -number: OFF -expver: 1 -repres: -target: /raid60/nas/tmc/Anne/Interpolation/flexextract/flex_extract_v7.1/python/../work/ANGG__ML.20170809.41511.90849.grb -step: 00 -grid: 32 -param: U/V/D/77 -time: 00/06/12/18 -date: 20170809/to/20170809 -resol: 63 -type: AN -accuracy: 24 - - -mars -gaussian: -stream: OPER -levelist: 1 -area: 40.0/-10.0/30.0/10.0 -marsclass: EI -levtype: ML -number: OFF -expver: 1 -repres: -target: /raid60/nas/tmc/Anne/Interpolation/flexextract/flex_extract_v7.1/python/../work/ANSH__SL.20170809.41511.90849.grb -step: 00 -grid: OFF -param: LNSP -time: 00/06/12/18 -date: 20170809/to/20170809 -resol: 63 -type: AN -accuracy: 24 - - -mars -gaussian: -stream: OPER -levelist: 1 -area: 40.0/-10.0/30.0/10.0 -marsclass: EI -levtype: SFC -number: OFF -expver: 1 -repres: -target: /raid60/nas/tmc/Anne/Interpolation/flexextract/flex_extract_v7.1/python/../work/ANOG__SL.20170809.41511.90849.grb -step: 00 -grid: 5.0/5.0 -param: 141/151/164/165/166/167/168/129/172/186/187/188/235/139/39 -time: 00/06/12/18 -date: 20170809/to/20170809 -resol: 63 -type: AN -accuracy: 24 - - diff --git a/setup.sh b/setup.sh index 0446f0a..18d3395 100755 --- a/setup.sh +++ b/setup.sh @@ -19,7 +19,7 @@ ECGID='at' GATEWAY='srvx8.img.univie.ac.at' DESTINATION='annep@genericSftp' FLEXPART_ROOT_SCRIPTS="" -JOB_TEMPLATE="" +JOB_TEMPLATE="job.temp.o" CONTROLFILE="CONTROL.test" # ----------------------------------------------------------------- # @@ -28,7 +28,7 @@ CONTROLFILE="CONTROL.test" # ----------------------------------------------------------------- # PATH TO INSTALLATION SCRIPT -script="python/install.py" +script="source/python/install.py" # INITIALIZE EMPTY PARAMETERLIST parameterlist="" diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/src/Makefile.CRAY b/source/fortran/Makefile.CRAY similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/src/Makefile.CRAY rename to source/fortran/Makefile.CRAY diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/src/Makefile.gfortran b/source/fortran/Makefile.gfortran similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/src/Makefile.gfortran rename to source/fortran/Makefile.gfortran diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/src/Makefile.ifort b/source/fortran/Makefile.ifort similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/src/Makefile.ifort rename to source/fortran/Makefile.ifort diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/src/Makefile.local.gfortran b/source/fortran/Makefile.local.gfortran similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/src/Makefile.local.gfortran rename to source/fortran/Makefile.local.gfortran diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/src/Makefile.local.ifort b/source/fortran/Makefile.local.ifort similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/src/Makefile.local.ifort rename to source/fortran/Makefile.local.ifort diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/src/Makefile.new b/source/fortran/Makefile.new similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/src/Makefile.new rename to source/fortran/Makefile.new diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/src/ftrafo.f b/source/fortran/ftrafo.f similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/src/ftrafo.f rename to source/fortran/ftrafo.f diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/src/grphreal.f b/source/fortran/grphreal.f similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/src/grphreal.f rename to source/fortran/grphreal.f diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/src/jparams.h b/source/fortran/jparams.h similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/src/jparams.h rename to source/fortran/jparams.h diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/src/phgrreal.f b/source/fortran/phgrreal.f similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/src/phgrreal.f rename to source/fortran/phgrreal.f diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/src/posnam.f b/source/fortran/posnam.f similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/src/posnam.f rename to source/fortran/posnam.f diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/src/preconvert.f90 b/source/fortran/preconvert.f90 similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/src/preconvert.f90 rename to source/fortran/preconvert.f90 diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/src/rwGRIB2.f90 b/source/fortran/rwGRIB2.f90 similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/src/rwGRIB2.f90 rename to source/fortran/rwGRIB2.f90 diff --git a/source/python/__init__.py b/source/python/__init__.py new file mode 100644 index 0000000..4609bf2 --- /dev/null +++ b/source/python/__init__.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +#******************************************************************************* +# @Author: Anne Philipp (University of Vienna) +# +# @Date: September 2018 +# +# @License: +# (C) Copyright 2015-2018. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# +#******************************************************************************* diff --git a/source/python/_config.py b/source/python/_config.py new file mode 100644 index 0000000..5b888d1 --- /dev/null +++ b/source/python/_config.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +#******************************************************************************* +# @Author: Anne Philipp (University of Vienna) +# +# @Date: August 2018 +# +# @Change History: +# +# @License: +# (C) Copyright 2014-2018. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# +# @Description: +# Contains constant value parameter for flex_extract. +# +#******************************************************************************* + +# ------------------------------------------------------------------------------ +# MODULES +# ------------------------------------------------------------------------------ +import os +import sys +import inspect + +_VERSION_STR = '7.1' + +# ------------------------------------------------------------------------------ +# FILENAMES +# ------------------------------------------------------------------------------ + +FILE_MARS_REQUESTS = 'mars_requests.dat' +FORTRAN_EXECUTABLE = 'CONVERT2' +FILE_USER_ENVVARS = 'ECMWF_ENV' +TEMPFILE_INSTALL_COMPILEJOB = 'compilejob.temp' +FILE_INSTALL_COMPILEJOB = 'compilejob.ksh' +TEMPFILE_INSTALL_JOB = 'job.temp.o' +TEMPFILE_JOB = 'job.temp' +FILE_JOB_OD = 'job.ksh' +FILE_JOB_OP = 'jopoper.ksh' +FILE_NAMELIST = 'fort.4' +FILE_GRIB_INDEX = 'date_time_stepRange.idx' +FILE_GRIBTABLE = 'ecmwf_grib1_table_128' + +# ------------------------------------------------------------------------------ +# DIRECTORY NAMES +# ------------------------------------------------------------------------------ + +FLEXEXTRACT_DIRNAME = 'flex_extract_v' + _VERSION_STR +INPUT_DIRNAME_DEFAULT = 'workspace' + +# ------------------------------------------------------------------------------ +# PATHES +# ------------------------------------------------------------------------------ + +# path to the local python source files +# first thing to get because the submitted python script starts in here +PATH_LOCAL_PYTHON = os.path.dirname(os.path.abspath( + inspect.getfile(inspect.currentframe()))) +# add path to pythonpath +if PATH_LOCAL_PYTHON not in sys.path: + sys.path.append(PATH_LOCAL_PYTHON) +PATH_FLEXEXTRACT_DIR = os.path.normpath(os.path.dirname(os.path.abspath( + inspect.getfile(inspect.currentframe()))) + '/../../') +PATH_RUN_DIR = os.path.join(PATH_FLEXEXTRACT_DIR, 'run') +PATH_SOURCES = os.path.join(PATH_FLEXEXTRACT_DIR, 'source') +PATH_TEMPLATES = os.path.join(PATH_FLEXEXTRACT_DIR, 'templates') +PATH_ECMWF_ENV = os.path.join(PATH_RUN_DIR, FILE_USER_ENVVARS) +PATH_GRIBTABLE = os.path.join(PATH_TEMPLATES, FILE_GRIBTABLE) +PATH_JOBSCRIPTS = os.path.join(PATH_RUN_DIR, 'jobscripts') +PATH_FORTRAN_SRC = os.path.join(PATH_SOURCES, 'fortran') +PATH_TEST_DIR = os.path.join(PATH_SOURCES, 'pythontest') +PATH_INPUT_DIR = os.path.join(PATH_RUN_DIR, INPUT_DIRNAME_DEFAULT) +if os.getenv('CONTROL') and '/' in os.getenv('CONTROL'): + # this is only needed if remote version with job script is used! + # because job is directly submitted from SCRATCH and because the + # CONTROL file is stored there, the normal path is not valid. + PATH_CONTROLFILES = os.getenv('CONTROL') +else: + PATH_CONTROLFILES = os.path.join(PATH_RUN_DIR, 'control') +# +# ------------------------------------------------------------------------------ +# for making the installation tar ball, the relative pathes to the +# flex_extract root directory are needed +# ------------------------------------------------------------------------------ + +PATH_REL_PYTHON = os.path.relpath(PATH_LOCAL_PYTHON, PATH_FLEXEXTRACT_DIR) +PATH_REL_CONTROLFILES = os.path.relpath(PATH_CONTROLFILES, PATH_FLEXEXTRACT_DIR) +PATH_REL_TEMPLATES = os.path.relpath(PATH_TEMPLATES, PATH_FLEXEXTRACT_DIR) +PATH_REL_ECMWF_ENV = os.path.relpath(PATH_ECMWF_ENV, PATH_FLEXEXTRACT_DIR) +PATH_REL_RUN_DIR = os.path.relpath(PATH_RUN_DIR, PATH_FLEXEXTRACT_DIR) +PATH_REL_JOBSCRIPTS = os.path.relpath(PATH_JOBSCRIPTS, PATH_FLEXEXTRACT_DIR) +PATH_REL_FORTRAN_SRC = os.path.relpath(PATH_FORTRAN_SRC, PATH_FLEXEXTRACT_DIR) diff --git a/python/ControlFile.py b/source/python/classes/ControlFile.py similarity index 99% rename from python/ControlFile.py rename to source/python/classes/ControlFile.py index 9acfd75..97e6989 100644 --- a/python/ControlFile.py +++ b/source/python/classes/ControlFile.py @@ -142,7 +142,7 @@ class ControlFile(object): self.grib2flexpart = 0 self.ecstorage = 0 self.ectrans = 0 - self.inputdir = '../work' + self.inputdir = _config.PATH_INPUT_DIR self.outputdir = self.inputdir self.ecmwfdatadir = _config.PATH_FLEXEXTRACT_DIR self.exedir = _config.PATH_FORTRAN_SRC @@ -176,7 +176,7 @@ class ControlFile(object): @Return: <nothing> ''' - from tools import my_error + from mods.tools import my_error # read whole CONTROL file with open(os.path.join(_config.PATH_CONTROLFILES, @@ -330,7 +330,7 @@ class ControlFile(object): @Return: <nothing> ''' - from tools import my_error + from mods.tools import my_error import numpy as np # check for having at least a starting date diff --git a/python/EcFlexpart.py b/source/python/classes/EcFlexpart.py similarity index 99% rename from python/EcFlexpart.py rename to source/python/classes/EcFlexpart.py index ece03dc..6f4fbae 100644 --- a/python/EcFlexpart.py +++ b/source/python/classes/EcFlexpart.py @@ -60,31 +60,12 @@ # - deacc_fluxes # # @Class Attributes: -# - dtime -# - basetime -# - server -# - marsclass -# - stream -# - resol -# - accuracy -# - number -# - expver -# - glevelist -# - area -# - grid -# - level -# - levelist -# - types -# - dates -# - area -# - gaussian -# - params -# - inputdir -# - outputfilelist +# +# TODO # #******************************************************************************* #pylint: disable=unsupported-assignment-operation -# this is disabled because its an error in pylint for this specific case +# this is disabled because for this specific case its an error in pylint #pylint: disable=consider-using-enumerate # this is not useful in this case # ------------------------------------------------------------------------------ @@ -103,9 +84,9 @@ from gribapi import grib_set, grib_index_select, grib_new_from_index, grib_get,\ # software specific classes and modules from flex_extract import _config from GribTools import GribTools -from tools import init128, to_param_id, silent_remove, product, my_error +from mods.tools import init128, to_param_id, silent_remove, product, my_error from MarsRetrieval import MarsRetrieval -import disaggregation +import mods.disaggregation # ------------------------------------------------------------------------------ # CLASS @@ -470,9 +451,9 @@ class EcFlexpart(object): MR.display_info() MR.data_retrieve() elif request == 1: - MR.print_info() + MR.print_info(self.inputdir) elif request == 2: - MR.print_info() + MR.print_info(self.inputdir) MR.display_info() MR.data_retrieve() else: diff --git a/python/GribTools.py b/source/python/classes/GribTools.py similarity index 100% rename from python/GribTools.py rename to source/python/classes/GribTools.py diff --git a/python/MarsRetrieval.py b/source/python/classes/MarsRetrieval.py similarity index 98% rename from python/MarsRetrieval.py rename to source/python/classes/MarsRetrieval.py index 755dcef..bb86f2b 100644 --- a/python/MarsRetrieval.py +++ b/source/python/classes/MarsRetrieval.py @@ -334,7 +334,7 @@ class MarsRetrieval(object): return - def print_info(self): + def print_info(self, inputdir): ''' @Description: Prints all mars requests to an extra file for debugging and @@ -344,6 +344,9 @@ class MarsRetrieval(object): self: instance of MarsRetrieval For description see class documentation. + inputdir: string + The path where all data from the retrievals are stored. + @Return: <nothing> ''' @@ -351,7 +354,7 @@ class MarsRetrieval(object): attrs = vars(self) # open a file to store all requests to - with open(os.path.join(_config.PATH_RUN_DIR, + with open(os.path.join(inputdir, _config.FILE_MARS_REQUESTS), 'a') as f: f.write('mars\n') # iterate through all attributes and print them diff --git a/python/UioFiles.py b/source/python/classes/UioFiles.py similarity index 76% rename from python/UioFiles.py rename to source/python/classes/UioFiles.py index fe69953..e9eaf86 100644 --- a/python/UioFiles.py +++ b/source/python/classes/UioFiles.py @@ -51,7 +51,7 @@ import fnmatch # software specific module from flex_extract #import profiling -from tools import silent_remove, get_list_as_string +from mods.tools import silent_remove, get_list_as_string # ------------------------------------------------------------------------------ # CLASS @@ -59,9 +59,9 @@ from tools import silent_remove, get_list_as_string class UioFiles(object): ''' - Class to manipulate files. At initialisation it has the attribute - pattern which stores a regular expression pattern for the files associated - with the instance of the class. + Class to manipulate files. At initialisation it has the pattern + which stores a regular expression pattern for the files, the path + to the files and the files already. ''' # -------------------------------------------------------------------------- # CLASS FUNCTIONS @@ -87,14 +87,14 @@ class UioFiles(object): self.path = path self.pattern = pattern - self.files = None + self.files = [] self.__list_files__(self.path) return #@profiling.timefn - def __list_files__(self, path, callid=0): + def __list_files__(self, path): ''' @Description: Lists all files in the directory with the matching @@ -107,35 +107,16 @@ class UioFiles(object): path: string Path to the files. - callid: integer - Id which tells the function if its the first call - or a recursive call. Default and first call is 0. - Everything different from 0 is ment to be a recursive case. - @Return: <nothing> ''' - - # initialize variable in first function call - if callid == 0: - self.files = [] - # Get the absolute path path = os.path.abspath(path) - # get the file list of the path if its not a directory and - # if it contains the pattern - self.files.extend([os.path.join(path, k) for k in os.listdir(path) - if fnmatch.fnmatch(k, self.pattern)]) - - # find possible sub-directories in the path - subdirs = [s for s in os.listdir(path) - if os.path.isdir(os.path.join(path, s))] - - # do recursive calls for sub-direcorties - if subdirs: - for subdir in subdirs: - self.__list_files__(os.path.join(path, subdir), callid=1) + # get all files in the dir and subdir as absolut path + for root, dirnames, filenames in os.walk(path): + for filename in fnmatch.filter(filenames, self.pattern): + self.files.append(os.path.join(root, filename)) return diff --git a/source/python/classes/__init__.py b/source/python/classes/__init__.py new file mode 100644 index 0000000..4609bf2 --- /dev/null +++ b/source/python/classes/__init__.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +#******************************************************************************* +# @Author: Anne Philipp (University of Vienna) +# +# @Date: September 2018 +# +# @License: +# (C) Copyright 2015-2018. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# +#******************************************************************************* diff --git a/python/install.py b/source/python/install.py similarity index 92% rename from python/install.py rename to source/python/install.py index 89610bf..9b0142d 100755 --- a/python/install.py +++ b/source/python/install.py @@ -57,9 +57,9 @@ from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter # software specific classes and modules from flex_extract import _config -from ControlFile import ControlFile -from UioFiles import UioFiles -from tools import make_dir, put_file_to_ecserver, submit_job_to_ecserver +from classes.ControlFile import ControlFile +from classes.UioFiles import UioFiles +from mods.tools import make_dir, put_file_to_ecserver, submit_job_to_ecserver # ------------------------------------------------------------------------------ # FUNCTIONS @@ -188,13 +188,13 @@ def install_via_gateway(c): mk_env_vars(c.ecuid, c.ecgid, c.gateway, c.destination) - mk_tarball(tar_file) + mk_tarball(tar_file, c.install_target) put_file_to_ecserver(ecd, tarball_name, c.install_target, c.ecuid, c.ecgid) submit_job_to_ecserver(c.install_target, - os.path.join(_config.PATH_RELATIVE_JOBSCRIPTS, + os.path.join(_config.PATH_REL_JOBSCRIPTS, _config.FILE_INSTALL_COMPILEJOB)) print('job compilation script has been submitted to ecgate for ' + @@ -213,7 +213,7 @@ def install_via_gateway(c): c.flexpart_root_scripts = os.path.expandvars(os.path.expanduser( c.flexpart_root_scripts)) if os.path.abspath(ecd) != os.path.abspath(c.flexpart_root_scripts): - mk_tarball(tar_file) + mk_tarball(tar_file, c.install_target) make_dir(os.path.join(c.flexpart_root_scripts, target_dirname)) os.chdir(os.path.join(c.flexpart_root_scripts, @@ -221,7 +221,7 @@ def install_via_gateway(c): un_tarball(tar_file) os.chdir(os.path.join(c.flexpart_root_scripts, target_dirname, - _config.PATH_RELATIVE_FORTRAN_SRC)) + _config.PATH_REL_FORTRAN_SRC)) # Create Fortran executable - CONVERT2 print('Install ' + target_dirname + ' software at ' + @@ -237,7 +237,7 @@ def install_via_gateway(c): return -def mk_tarball(tarball_path): +def mk_tarball(tarball_path, target): ''' @Description: Creates a tarball with all necessary files which need to be sent to the @@ -252,6 +252,9 @@ def mk_tarball(tarball_path): The complete path to the tar file which will contain all relevant data for flex_extract. + target: string + The queue where the job is submitted to. + @Return: <nothing> ''' @@ -266,25 +269,24 @@ def mk_tarball(tarball_path): os.chdir(ecd) # get lists of the files to be added to the tar file - ECMWF_ENV_FILE = [_config.PATH_RELATIVE_ECMWF_ENV] + if target == 'local': + ECMWF_ENV_FILE = [] + else: + ECMWF_ENV_FILE = [_config.PATH_REL_ECMWF_ENV] + pyfiles = [os.path.relpath(x, ecd) - for x in glob(_config.PATH_LOCAL_PYTHON + - os.path.sep + '*py')] + for x in UioFiles(_config.PATH_LOCAL_PYTHON, '*py').files] controlfiles = [os.path.relpath(x, ecd) - for x in glob(_config.PATH_CONTROLFILES + - os.path.sep + 'CONTROL*')] + for x in UioFiles(_config.PATH_CONTROLFILES, + 'CONTROL*').files] tempfiles = [os.path.relpath(x, ecd) - for x in glob(_config.PATH_TEMPLATES + - os.path.sep + '*')] + for x in UioFiles(_config.PATH_TEMPLATES , '*').files] ffiles = [os.path.relpath(x, ecd) - for x in glob(_config.PATH_FORTRAN_SRC + - os.path.sep + '*.f*')] + for x in UioFiles(_config.PATH_FORTRAN_SRC, '*.f*').files] hfiles = [os.path.relpath(x, ecd) - for x in glob(_config.PATH_FORTRAN_SRC + - os.path.sep + '*.h')] + for x in UioFiles(_config.PATH_FORTRAN_SRC, '*.h').files] makefiles = [os.path.relpath(x, ecd) - for x in glob(_config.PATH_FORTRAN_SRC + - os.path.sep + 'Makefile*')] + for x in UioFiles(_config.PATH_FORTRAN_SRC, 'Makefile*').files] # concatenate single lists to one for a better looping filelist = pyfiles + controlfiles + tempfiles + ffiles + hfiles + \ @@ -351,7 +353,7 @@ def mk_env_vars(ecuid, ecgid, gateway, destination): <nothing> ''' - with open(_config.PATH_RELATIVE_ECMWF_ENV, 'w') as fo: + with open(_config.PATH_REL_ECMWF_ENV, 'w') as fo: fo.write('ECUID ' + ecuid + '\n') fo.write('ECGID ' + ecgid + '\n') fo.write('GATEWAY ' + gateway + '\n') @@ -388,12 +390,12 @@ def mk_compilejob(makefile, target, ecuid, ecgid, fp_root): <nothing> ''' - template = os.path.join(_config.PATH_RELATIVE_TEMPLATES, + template = os.path.join(_config.PATH_REL_TEMPLATES, _config.TEMPFILE_INSTALL_COMPILEJOB) with open(template) as f: fdata = f.read().split('\n') - compilejob = os.path.join(_config.PATH_RELATIVE_JOBSCRIPTS, + compilejob = os.path.join(_config.PATH_REL_JOBSCRIPTS, _config.FILE_INSTALL_COMPILEJOB) with open(compilejob, 'w') as fo: for data in fdata: @@ -449,14 +451,14 @@ def mk_job_template(ecuid, ecgid, gateway, destination, fp_root): <nothing> ''' fp_root_path_to_python = os.path.join(fp_root, _config.FLEXEXTRACT_DIRNAME, - _config.PATH_RELATIVE_PYTHON) + _config.PATH_REL_PYTHON) - template = os.path.join(_config.PATH_RELATIVE_TEMPLATES, + template = os.path.join(_config.PATH_REL_TEMPLATES, _config.TEMPFILE_INSTALL_JOB) with open(template) as f: fdata = f.read().split('\n') - jobfile_temp = os.path.join(_config.PATH_RELATIVE_TEMPLATES, + jobfile_temp = os.path.join(_config.PATH_REL_TEMPLATES, _config.TEMPFILE_JOB) with open(jobfile_temp, 'w') as fo: for data in fdata: diff --git a/source/python/mods/__init__.py b/source/python/mods/__init__.py new file mode 100644 index 0000000..4609bf2 --- /dev/null +++ b/source/python/mods/__init__.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +#******************************************************************************* +# @Author: Anne Philipp (University of Vienna) +# +# @Date: September 2018 +# +# @License: +# (C) Copyright 2015-2018. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# +#******************************************************************************* diff --git a/python/disaggregation.py b/source/python/mods/disaggregation.py similarity index 100% rename from python/disaggregation.py rename to source/python/mods/disaggregation.py diff --git a/python/get_mars_data.py b/source/python/mods/get_mars_data.py similarity index 99% rename from python/get_mars_data.py rename to source/python/mods/get_mars_data.py index 07dfd78..1ccdfa9 100755 --- a/python/get_mars_data.py +++ b/source/python/mods/get_mars_data.py @@ -58,8 +58,8 @@ except ImportError: # software specific classes and modules from flex_extract import _config from tools import my_error, normal_exit, get_cmdline_arguments, read_ecenv -from EcFlexpart import EcFlexpart -from UioFiles import UioFiles +from classes.EcFlexpart import EcFlexpart +from classes.UioFiles import UioFiles # ------------------------------------------------------------------------------ # FUNCTION # ------------------------------------------------------------------------------ diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/plot_retrieved.py b/source/python/mods/plot_retrieved.py similarity index 98% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/python/plot_retrieved.py rename to source/python/mods/plot_retrieved.py index 45e7bb2..21e27e7 100755 --- a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/plot_retrieved.py +++ b/source/python/mods/plot_retrieved.py @@ -52,14 +52,9 @@ from eccodes import codes_grib_new_from_file, codes_get, codes_release, \ import numpy as np # software specific classes and modules from flex_extract -from ControlFile import ControlFile -from UioFiles import UioFiles - -# add path to pythonpath so that python finds its buddies -LOCAL_PYTHON_PATH = os.path.dirname(os.path.abspath( - inspect.getfile(inspect.currentframe()))) -if LOCAL_PYTHON_PATH not in sys.path: - sys.path.append(LOCAL_PYTHON_PATH) +import _config +from classes.ControlFile import ControlFile +from classes.UioFiles import UioFiles font = {'family': 'monospace', 'size': 12} matplotlib.rcParams['xtick.major.pad'] = '20' diff --git a/python/prepare_flexpart.py b/source/python/mods/prepare_flexpart.py similarity index 98% rename from python/prepare_flexpart.py rename to source/python/mods/prepare_flexpart.py index 9ea7868..4ac0af8 100755 --- a/python/prepare_flexpart.py +++ b/source/python/mods/prepare_flexpart.py @@ -59,9 +59,9 @@ import socket # software specific classes and modules from flex_extract import _config -from UioFiles import UioFiles +from classes.UioFiles import UioFiles from tools import clean_up, get_cmdline_arguments, read_ecenv -from EcFlexpart import EcFlexpart +from classes.EcFlexpart import EcFlexpart ecapi = 'ecmwf' not in socket.gethostname() try: diff --git a/python/profiling.py b/source/python/mods/profiling.py similarity index 100% rename from python/profiling.py rename to source/python/mods/profiling.py diff --git a/python/tools.py b/source/python/mods/tools.py similarity index 100% rename from python/tools.py rename to source/python/mods/tools.py diff --git a/python/submit.py b/source/python/submit.py similarity index 96% rename from python/submit.py rename to source/python/submit.py index 2cd757e..9819583 100755 --- a/python/submit.py +++ b/source/python/submit.py @@ -50,11 +50,11 @@ import collections # software specific classes and modules from flex_extract import _config -from tools import normal_exit, get_cmdline_arguments, submit_job_to_ecserver, \ - read_ecenv -from get_mars_data import get_mars_data -from prepare_flexpart import prepare_flexpart -from ControlFile import ControlFile +from mods.tools import (normal_exit, get_cmdline_arguments, + submit_job_to_ecserver, read_ecenv) +from mods.get_mars_data import get_mars_data +from mods.prepare_flexpart import prepare_flexpart +from classes.ControlFile import ControlFile # ------------------------------------------------------------------------------ # FUNCTIONS diff --git a/python/pythontest/.coverage b/source/pythontest/.coverage similarity index 100% rename from python/pythontest/.coverage rename to source/pythontest/.coverage diff --git a/python/pythontest/TestData/CONTROL.temp b/source/pythontest/TestData/CONTROL.temp similarity index 100% rename from python/pythontest/TestData/CONTROL.temp rename to source/pythontest/TestData/CONTROL.temp diff --git a/python/pythontest/TestData/ECMWF_ENV b/source/pythontest/TestData/ECMWF_ENV similarity index 100% rename from python/pythontest/TestData/ECMWF_ENV rename to source/pythontest/TestData/ECMWF_ENV diff --git a/python/pythontest/TestData/testfile.txt b/source/pythontest/TestData/testfile.txt similarity index 100% rename from python/pythontest/TestData/testfile.txt rename to source/pythontest/TestData/testfile.txt diff --git a/python/pythontest/TestDir/FCOG__ML.20160410.40429.16424.grb b/source/pythontest/TestDir/FCOG__ML.20160410.40429.16424.grb similarity index 100% rename from python/pythontest/TestDir/FCOG__ML.20160410.40429.16424.grb rename to source/pythontest/TestDir/FCOG__ML.20160410.40429.16424.grb diff --git a/python/pythontest/TestDir/FCOG__SL.20160410.40429.16424.grb b/source/pythontest/TestDir/FCOG__SL.20160410.40429.16424.grb similarity index 100% rename from python/pythontest/TestDir/FCOG__SL.20160410.40429.16424.grb rename to source/pythontest/TestDir/FCOG__SL.20160410.40429.16424.grb diff --git a/python/pythontest/TestDir/FCSH__ML.20160410.40429.16424.grb b/source/pythontest/TestDir/FCSH__ML.20160410.40429.16424.grb similarity index 100% rename from python/pythontest/TestDir/FCSH__ML.20160410.40429.16424.grb rename to source/pythontest/TestDir/FCSH__ML.20160410.40429.16424.grb diff --git a/python/pythontest/TestDir/FCSH__SL.20160410.40429.16424.grb b/source/pythontest/TestDir/FCSH__SL.20160410.40429.16424.grb similarity index 100% rename from python/pythontest/TestDir/FCSH__SL.20160410.40429.16424.grb rename to source/pythontest/TestDir/FCSH__SL.20160410.40429.16424.grb diff --git a/python/pythontest/TestDir/SubTestDir/OG_OROLSM__SL.20160410.40429.16424.grb b/source/pythontest/TestDir/SubTestDir/OG_OROLSM__SL.20160410.40429.16424.grb similarity index 100% rename from python/pythontest/TestDir/SubTestDir/OG_OROLSM__SL.20160410.40429.16424.grb rename to source/pythontest/TestDir/SubTestDir/OG_OROLSM__SL.20160410.40429.16424.grb diff --git a/python/pythontest/TestDir/SubTestDir/SubSubTestDir/FCGG__SL.20160410.40429.16424.grb b/source/pythontest/TestDir/SubTestDir/SubSubTestDir/FCGG__SL.20160410.40429.16424.grb similarity index 100% rename from python/pythontest/TestDir/SubTestDir/SubSubTestDir/FCGG__SL.20160410.40429.16424.grb rename to source/pythontest/TestDir/SubTestDir/SubSubTestDir/FCGG__SL.20160410.40429.16424.grb diff --git a/python/pythontest/TestDir/SubTestDir2/FCOG_acc_SL.20160409.40429.16424.grb b/source/pythontest/TestDir/SubTestDir2/FCOG_acc_SL.20160409.40429.16424.grb similarity index 100% rename from python/pythontest/TestDir/SubTestDir2/FCOG_acc_SL.20160409.40429.16424.grb rename to source/pythontest/TestDir/SubTestDir2/FCOG_acc_SL.20160409.40429.16424.grb diff --git a/python/pythontest/TestEcFlexpart.py b/source/pythontest/TestEcFlexpart.py similarity index 52% rename from python/pythontest/TestEcFlexpart.py rename to source/pythontest/TestEcFlexpart.py index d256084..e1b7a9c 100644 --- a/python/pythontest/TestEcFlexpart.py +++ b/source/pythontest/TestEcFlexpart.py @@ -1,31 +1,29 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import unittest + import sys -import EcFlexpart +import pytest sys.path.append('../python') +from classes.EcFlexpart import EcFlexpart -class TestEcFlexpart(unittest.TestCase): +class TestEcFlexpart(): ''' ''' - def setUp(self): - pass - - def test__init__(): - # create an instance of EcFlexpart and get a dictionary of the - # class attributes, compare this dict with an expected dict! - return + def test_init(self): + # create an instance of EcFlexpart and get a dictionary of the + # class attributes, compare this dict with an expected dict! + assert True == True - def test_write_namelist(): + def test_write_namelist(self): # simple - return + assert True == True - def test_retrieve(): + def test_retrieve(self): # not sure how to check - return + assert True == True # these functions should test the output and compare the results with an output @@ -35,9 +33,3 @@ class TestEcFlexpart(unittest.TestCase): # - process_output # - create # - deacc_fluxes - - - - -if __name__ == "__main__": - unittest.main() \ No newline at end of file diff --git a/python/pythontest/TestInput.py b/source/pythontest/TestInput.py similarity index 93% rename from python/pythontest/TestInput.py rename to source/pythontest/TestInput.py index 61bede1..ff19076 100644 --- a/python/pythontest/TestInput.py +++ b/source/pythontest/TestInput.py @@ -1,16 +1,16 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import unittest import os import sys +import pytest sys.path.append('../python') -from ControlFile import ControlFile -import tools +from classes.ControlFile import ControlFile +from mods.tools import get_cmdline_arguments -class TestInput(unittest.TestCase): +class TestInput(): ''' Test class to test the reading of commandline arguments and control file. @@ -20,9 +20,7 @@ class TestInput(unittest.TestCase): # 1. nur controlfile reading # 2. check of parameter - def setUp(self): - ''' - ''' + def __init__(self): # Default values for ArgumentParser self.args = {'start_date':None, 'end_date':None, @@ -52,14 +50,13 @@ class TestInput(unittest.TestCase): self.c.check_conditions() - return def test_args_reading(self): sys.argv = ['dummy.py', '--start_date=20180101', '--debug=1', '--step=0/to/11/BY/3', '--area=20./20./0./90.'] - arguments = tools.get_commandline_arguments() + arguments = tools.get_cmdline_arguments() args_exp = {'start_date':'20180101', 'end_date':None, @@ -78,8 +75,8 @@ class TestInput(unittest.TestCase): 'debug':1, } - self.assertDictEqual(vars(arguments), args_exp) - return + assert vars(arguments) == args_exp + def test_args_assignment(self): @@ -157,9 +154,6 @@ class TestInput(unittest.TestCase): #print 'exp_dict\n', exp_dict #assert cdict == exp_dict - self.assertDictEqual(cdict, exp_dict) + assert cdict == exp_dict return - -if __name__ == "__main__": - unittest.main() diff --git a/python/pythontest/TestInstall.py b/source/pythontest/TestInstall.py similarity index 52% rename from python/pythontest/TestInstall.py rename to source/pythontest/TestInstall.py index deff522..6691d06 100644 --- a/python/pythontest/TestInstall.py +++ b/source/pythontest/TestInstall.py @@ -1,22 +1,22 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import unittest + import sys import os import inspect -sys.path.append('../') +import pytest + +sys.path.append('../python') import _config import install -from tools import make_dir +from mods.tools import make_dir -class TestTools(unittest.TestCase): +class TestTools(): ''' ''' - def setUp(self): - pass # - main # - get_install_cmdline_arguments @@ -29,7 +29,7 @@ class TestTools(unittest.TestCase): # - delete_convert_build # - make_convert_build - def test_mk_tarball(self): + def test_mk_tarball_local(self): import tarfile ecd = _config.PATH_FLEXEXTRACT_DIR + os.path.sep @@ -37,17 +37,40 @@ class TestTools(unittest.TestCase): # list comparison files for tarball content tar_test_dir = os.path.join(_config.PATH_TEST_DIR + os.path.sep + 'TestInstallTar') - tar_test_fedir = os.path.join(tar_test_dir, 'flex_extract_v7.1') + tar_test_file = os.path.join(tar_test_dir, + 'flex_extract_v7.1_local.tar') + with tarfile.open(tar_test_file, 'r') as tar_handle: + comparison_list = tar_handle.getnames() - comparison_list = [] - for path, subdirs, files in os.walk(tar_test_fedir): - for name in files: - if 'tar' not in name: - comparison_list.append(os.path.relpath(os.path.join(path, name), tar_test_fedir)) + # create test tarball and list its content files + tarballname = _config.FLEXEXTRACT_DIRNAME + '_localtest.tar' + install.mk_tarball(ecd + tarballname, 'local') + with tarfile.open(ecd + tarballname, 'r') as tar_handle: + tar_content_list = tar_handle.getnames() + + # remove test tar file from flex_extract directory + os.remove(ecd + tarballname) + + # test if comparison filelist is equal to the + # filelist of tarball content + assert sorted(comparison_list) == sorted(tar_content_list) + + def test_mk_tarball_ecgate(self): + import tarfile + + ecd = _config.PATH_FLEXEXTRACT_DIR + os.path.sep + + # list comparison files for tarball content + tar_test_dir = os.path.join(_config.PATH_TEST_DIR + + os.path.sep + 'TestInstallTar') + tar_test_file = os.path.join(tar_test_dir, + 'flex_extract_v7.1_ecgate.tar') + with tarfile.open(tar_test_file, 'r') as tar_handle: + comparison_list = tar_handle.getnames() # create test tarball and list its content files - tarballname = _config.FLEXEXTRACT_DIRNAME + '_test.tar' - install.mk_tarball(ecd + tarballname) + tarballname = _config.FLEXEXTRACT_DIRNAME + '_ecgatetest.tar' + install.mk_tarball(ecd + tarballname, 'ecgate') with tarfile.open(ecd + tarballname, 'r') as tar_handle: tar_content_list = tar_handle.getnames() @@ -67,30 +90,28 @@ class TestTools(unittest.TestCase): # list comparison files for tarball content tar_test_dir = os.path.join(_config.PATH_TEST_DIR + os.path.sep + 'TestInstallTar') - tar_test_fedir = os.path.join(tar_test_dir, 'flex_extract_v7.1') + tar_test_fedir = os.path.join(tar_test_dir, 'flex_extract_v7.1_ecgate') comparison_list = [] for path, subdirs, files in os.walk(tar_test_fedir): for name in files: if 'tar' not in name: - comparison_list.append(os.path.relpath(os.path.join(path, name), tar_test_fedir)) + comparison_list.append(os.path.relpath( + os.path.join(path, name), tar_test_fedir)) # untar in test directory test_dir = os.path.join(tar_test_dir, 'test_untar') make_dir(test_dir) os.chdir(test_dir) - tarballname = _config.FLEXEXTRACT_DIRNAME + '.tar' + tarballname = _config.FLEXEXTRACT_DIRNAME + '_ecgate.tar' install.un_tarball(os.path.join(tar_test_dir, tarballname)) tarfiles_list = [] for path, subdirs, files in os.walk(test_dir): for name in files: - tarfiles_list.append(os.path.relpath(os.path.join(path, name), test_dir)) + tarfiles_list.append(os.path.relpath( + os.path.join(path, name), test_dir)) # test for equality assert sorted(tarfiles_list) == sorted(comparison_list) # clean up temp test dir shutil.rmtree(test_dir) - - -if __name__ == "__main__": - unittest.main() diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/ECMWF_ENV b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/ECMWF_ENV similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/python/ECMWF_ENV rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/ECMWF_ENV diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.temp b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.temp new file mode 100644 index 0000000..b972567 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.temp @@ -0,0 +1,37 @@ +DAY1 20130501 +DAY2 +DTIME 3 +TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC +TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12 +STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11 +CLASS EI +STREAM OPER +NUMBER OFF +EXPVER 1 +GRID 5000 +LEFT -15000 +LOWER 30000 +UPPER 75000 +RIGHT 45000 +LEVEL 60 +LEVELIST 55/to/60 +RESOL 63 +GAUSS 1 +ACCURACY 16 +OMEGA 0 +OMEGADIFF 0 +ETA 0 +ETADIFF 0 +DPDETA 1 +SMOOTH 0 +FORMAT GRIB1 +ADDPAR 186/187/188/235/139/39 +PREFIX EI +ECSTORAGE 0 +ECTRANS 1 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILFAIL ${USER} +MAILOPS ${USER} +GRIB2FLEXPART 0 +EOF + diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.temp.backup b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.temp.backup new file mode 100644 index 0000000..2ee9992 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.temp.backup @@ -0,0 +1,37 @@ +DAY1 +DAY2 +DTIME 3 +TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC +TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12 +STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11 +CLASS EI +STREAM OPER +NUMBER OFF +EXPVER 1 +GRID 5000 +LEFT -175000 +LOWER -90000 +UPPER 90000 +RIGHT 180000 +LEVEL 60 +LEVELIST 1/to/60 +RESOL 63 +GAUSS 1 +ACCURACY 16 +OMEGA 0 +OMEGADIFF 0 +ETA 0 +ETADIFF 0 +DPDETA 1 +SMOOTH 0 +FORMAT GRIB1 +ADDPAR 186/187/188/235/139/39 +PREFIX EN +ECSTORAGE 1 +ECTRANS 0 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILFAIL ${USER} +MAILOPS ${USER} +GRIB2FLEXPART 0 +EOF + diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/run/control/CONTROL.test b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.test similarity index 97% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/run/control/CONTROL.test rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.test index b693ee4..41018e1 100644 --- a/python/pythontest/TestInstallTar/flex_extract_v7.1/run/control/CONTROL.test +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.test @@ -15,4 +15,4 @@ RESOL 63 GAUSS 1 ADDPAR 186/187/188/235/139/39 PREFIX EItest_ -ECTRANS 1 +ECTRANS 1 \ No newline at end of file diff --git a/python/pythontest/TestInstallTar/test_untar/run/control/CONTROL.test b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.worktest similarity index 60% rename from python/pythontest/TestInstallTar/test_untar/run/control/CONTROL.test rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.worktest index b693ee4..7bd637d 100644 --- a/python/pythontest/TestInstallTar/test_untar/run/control/CONTROL.test +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL.worktest @@ -1,18 +1,37 @@ +DAY1 20100101 +DAY2 DTIME 3 TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12 STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11 CLASS EI STREAM OPER +NUMBER OFF EXPVER 1 GRID 5000 LEFT -10000 LOWER 30000 UPPER 40000 RIGHT 10000 -LEVELIST 59/to/60 +LEVEL 60 +LEVELIST 58/to/60 RESOL 63 GAUSS 1 +ACCURACY 16 +OMEGA 0 +OMEGADIFF 0 +ETA 0 +ETADIFF 0 +DPDETA 1 +SMOOTH 0 +FORMAT GRIB1 ADDPAR 186/187/188/235/139/39 -PREFIX EItest_ +PREFIX EI +ECSTORAGE 0 ECTRANS 1 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILFAIL ${USER} +MAILOPS ${USER} +GRIB2FLEXPART 0 +EOF + diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_CV b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_CV new file mode 100644 index 0000000..39befc5 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_CV @@ -0,0 +1,37 @@ +DAY1 +DAY2 +DTIME 3 +MAXSTEP 36 +TYPE CF CF +TIME 12 12 +STEP 00 01 +CLASS OD +STREAM ENFO +NUMBER OFF +EXPVER 1 +GRID 1000 +LEFT -179000 +LOWER -90000 +UPPER 90000 +RIGHT 180000 +LEVEL 62 +LEVELIST 1/to/62 +RESOL 159 +GAUSS 1 +ACCURACY 16 +OMEGA 1 +OMEGADIFF 0 +ETA 0 +ETADIFF 0 +DPDETA 1 +SMOOTH 0 +FORMAT GRIB1 +ADDPAR /186/187/188/235/139/39 +PREFIX EE +ECSTORAGE 1 +ECTRANS 1 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILOPS ${USER} +MAILFAIL ${USER} +GRIB2FLEXPART 1 +EOF diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_CV_PREOP b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_CV_PREOP new file mode 100644 index 0000000..24364a3 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_CV_PREOP @@ -0,0 +1,37 @@ +DAY1 +DAY2 +DTIME 3 +MAXSTEP 36 +TYPE CV CV +TIME 12 12 +STEP 00 01 +CLASS OD +STREAM ENFO +NUMBER 1 +EXPVER 1 +GRID 1000 +LEFT -179000 +LOWER -90000 +UPPER 90000 +RIGHT 180000 +LEVEL 91 +LEVELIST 1/to/91 +RESOL 159 +GAUSS 1 +ACCURACY 16 +OMEGA 1 +OMEGADIFF 0 +ETA 0 +ETADIFF 0 +DPDETA 1 +SMOOTH 0 +FORMAT GRIB1 +ADDPAR /186/187/188/235/139/39 +PREFIX EN +ECSTORAGE 1 +ECTRANS 1 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILOPS ${USER} +MAILFAIL ${USER} +GRIB2FLEXPART 1 +EOF diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_DELIA_HR b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_DELIA_HR new file mode 100644 index 0000000..49c0c14 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_DELIA_HR @@ -0,0 +1,34 @@ +DAY1 20140918 +DAY2 20140920 +DTIME 3 +M_TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC +M_TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12 +M_STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11 +M_CLASS OD +M_STREAM OPER +M_NUMBER OFF +M_EXPVER 1 +M_GRID 500 +M_LEFT 12000 +M_LOWER 47000 +M_UPPER 52000 +M_RIGHT 17000 +M_LEVEL 137 +M_RESOL 511 +M_GAUSS 0 +M_ACCURACY 24 +M_OMEGA 0 +M_OMEGADIFF 0 +M_ETA 1 +M_ETADIFF 0 +M_DPDETA 1 +M_SMOOTH 0 +M_FORMAT GRIB2 +M_ADDPAR 186/187/188/235/139/39 +PREFIX EN +ECSTORAGE 1 +ECTRANS 0 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILOPS ${USER} +MAILFAIL ${USER} +EOF diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_DELIA_LR b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_DELIA_LR new file mode 100644 index 0000000..b3b0f2c --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_DELIA_LR @@ -0,0 +1,34 @@ +DAY1 20140918 +DAY2 20140920 +DTIME 3 +M_TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC +M_TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12 +M_STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11 +M_CLASS OD +M_STREAM OPER +M_NUMBER OFF +M_EXPVER 1 +M_GRID 1000 +M_LEFT 10000 +M_LOWER 45000 +M_UPPER 55000 +M_RIGHT 20000 +M_LEVEL 137 +M_RESOL 511 +M_GAUSS 0 +M_ACCURACY 24 +M_OMEGA 0 +M_OMEGADIFF 0 +M_ETA 1 +M_ETADIFF 0 +M_DPDETA 1 +M_SMOOTH 0 +M_FORMAT GRIB2 +M_ADDPAR 186/187/188/235/139/39 +PREFIX EN +ECSTORAGE 1 +ECTRANS 0 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILOPS ${USER} +MAILFAIL ${USER} +EOF diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_EI b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_EI new file mode 100644 index 0000000..c3d0974 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_EI @@ -0,0 +1,37 @@ +DAY1 +DAY2 +DTIME 3 +TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC +TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12 +STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11 +CLASS EI +STREAM OPER +NUMBER OFF +EXPVER 1 +GRID 5000 +LEFT -15000 +LOWER 30000 +UPPER 75000 +RIGHT 45000 +LEVEL 60 +LEVELIST 55/to/60 +RESOL 63 +GAUSS 1 +ACCURACY 16 +OMEGA 0 +OMEGADIFF 0 +ETA 0 +ETADIFF 0 +DPDETA 1 +SMOOTH 0 +FORMAT GRIB1 +ADDPAR 186/187/188/235/139/39 +PREFIX EI +ECSTORAGE 0 +ECTRANS 1 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILFAIL ${USER} +MAILOPS ${USER} +GRIB2FLEXPART 0 +EOF + diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_ERA_HAIYAN b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_ERA_HAIYAN new file mode 100644 index 0000000..a3e4b06 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_ERA_HAIYAN @@ -0,0 +1,34 @@ +DAY1 20131107 +DAY2 20131108 +DTIME 3 +M_TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC +M_TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12 +M_STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11 +M_CLASS OD +M_STREAM OPER +M_NUMBER OFF +M_EXPVER 1 +M_GRID 200 +M_LEFT 113000 +M_LOWER 00000 +M_UPPER 30000 +M_RIGHT 190000 +M_LEVEL 137 +M_RESOL 799 +M_GAUSS 0 +M_ACCURACY 24 +M_OMEGA 0 +M_OMEGADIFF 0 +M_ETA 1 +M_ETADIFF 0 +M_DPDETA 1 +M_SMOOTH 0 +M_FORMAT GRIB1 +M_ADDPAR /186/187/188/235/139/39 +PREFIX EH +ECSTORAGE 1 +ECTRANS 0 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILOPS ${USER} +MAILFAIL ${USER} +EOF diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_ERA__GLOBALETA b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_ERA__GLOBALETA new file mode 100644 index 0000000..4c43367 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_ERA__GLOBALETA @@ -0,0 +1,37 @@ +DAY1 20131105 +DAY2 20131105 +DTIME 3 +TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC +TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12 +STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11 +CLASS EI +STREAM OPER +NUMBER OFF +EXPVER 1 +GRID 1000 +LEFT -179000 +LOWER -90000 +UPPER 90000 +RIGHT 180000 +LEVEL 60 +LEVELIST 1/to/60 +RESOL 159 +GAUSS 1 +ACCURACY 16 +OMEGA 0 +OMEGADIFF 0 +ETA 0 +ETADIFF 0 +DPDETA 1 +SMOOTH 0 +FORMAT GRIB1 +ADDPAR /186/187/188/235/139/39 +PREFIX EE +ECSTORAGE 1 +ECTRANS 1 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILOPS ${USER} +MAILFAIL ${USER} +FLEXPARTDIR ${HOME}/ECMWFDATA7.0/flexpart_code +GRIB2FLEXPART grib2flexpart +EOF diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_ERA__HIRES b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_ERA__HIRES new file mode 100644 index 0000000..3ff11aa --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_ERA__HIRES @@ -0,0 +1,34 @@ +DAY1 20151007 +DAY2 20151007 +DTIME 1 +M_TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC +M_TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12 +M_STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11 +M_CLASS OD +M_STREAM OPER +M_NUMBER OFF +M_EXPVER 1 +M_GRID 200 +M_LEFT -10000 +M_LOWER 30000 +M_UPPER 60000 +M_RIGHT 30000 +M_LEVEL 137 +M_RESOL 799 +M_GAUSS 1 +M_ACCURACY 24 +M_OMEGA 0 +M_OMEGADIFF 0 +M_ETA 0 +M_ETADIFF 0 +M_DPDETA 1 +M_SMOOTH 0 +M_FORMAT GRIB1 +M_ADDPAR /186/187/188/235/139/39 +PREFIX EH +ECSTORAGE 1 +ECTRANS 0 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILOPS ${USER} +MAILFAIL ${USER} +EOF diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_FC b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_FC new file mode 100644 index 0000000..e05bac2 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_FC @@ -0,0 +1,31 @@ +DAY1 +DAY2 +DTIME 3 +M_TYPE FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC +M_TIME 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +M_STEP 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 +ACCTYPE FC +ACCTIME 00 +ACCMAXSTEP 36 +M_MAXSTEP 36 +M_LEVEL 137 +M_LEVELIST 136/to/137 +M_CLASS OD +M_STREAM OPER +M_NUMBER OFF +M_EXPVER 1 +M_GRID 1000 +M_LEFT -25000 +M_LOWER 10000 +M_UPPER 60000 +M_RIGHT 60000 +M_RESOL 159 +M_ETA 1 +M_DPDETA 1 +M_SMOOTH 0 +M_ADDPAR /186/187/188/235/139/39 +M_WRF 1 +M_CWC 1 +PREFIX EE +ECTRANS 1 +EOF diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_FC12 b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_FC12 new file mode 100644 index 0000000..1fcedce --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_FC12 @@ -0,0 +1,38 @@ +DAY1 20131107 +DAY2 20131108 +DTIME 3 +M_TYPE FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC +M_TIME 00 00 00 00 00 00 00 00 00 00 00 00 12 12 12 12 12 12 12 12 12 12 12 12 +M_STEP 00 01 02 03 04 05 06 07 08 09 10 11 00 01 02 03 04 05 06 07 08 09 10 11 +M_MAXSTEP 12 +M_LEVEL 137 +M_LEVELIST 120/to/121 +M_CLASS OD +M_STREAM OPER +M_NUMBER OFF +M_EXPVER 1 +M_GRID 1000 +M_LEFT -179000 +M_LOWER -90000 +M_UPPER 90000 +M_RIGHT 180000 +M_RESOL 159 +M_GAUSS 0 +M_ACCURACY 24 +M_OMEGA 0 +M_OMEGADIFF 0 +M_ETA 1 +M_ETADIFF 0 +M_DPDETA 1 +M_SMOOTH 0 +M_FORMAT GRIB1 +M_ADDPAR /186/187/188/235/139/39 +M_WRF 1 +M_CWC 1 +PREFIX EE +ECSTORAGE 1 +ECTRANS 0 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILOPS ${USER} +MAILFAIL ${USER} +EOF diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_HIRES b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_HIRES new file mode 100644 index 0000000..b2a2cf7 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_HIRES @@ -0,0 +1,34 @@ +DAY1 20151007 +DAY2 20151007 +DTIME 1 +M_TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC +M_TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12 +M_STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11 +M_CLASS OD +M_STREAM OPER +M_NUMBER OFF +M_EXPVER 1 +M_GRID 200 +M_LEFT -10000 +M_LOWER 30000 +M_UPPER 60000 +M_RIGHT 30000 +M_LEVEL 137 +M_RESOL 1279 +M_GAUSS 0 +M_ACCURACY 16 +M_OMEGA 0 +M_OMEGADIFF 0 +M_ETA 1 +M_ETADIFF 0 +M_DPDETA 1 +M_SMOOTH 0 +M_FORMAT GRIB1 +M_ADDPAR 186/187/188/235/139/39 +PREFIX EH +ECSTORAGE 1 +ECTRANS 0 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILOPS ${USER} +MAILFAIL ${USER} +EOF diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_HIRESGAUSS b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_HIRESGAUSS new file mode 100644 index 0000000..66abd64 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_HIRESGAUSS @@ -0,0 +1,34 @@ +DAY1 20151007 +DAY2 20151007 +DTIME 3 +M_TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC +M_TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12 +M_STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11 +M_CLASS OD +M_STREAM OPER +M_NUMBER OFF +M_EXPVER 1 +M_GRID 200 +M_LEFT -10000 +M_LOWER 30000 +M_UPPER 60000 +M_RIGHT 30000 +M_LEVEL 137 +M_RESOL 1279 +M_GAUSS 1 +M_ACCURACY 16 +M_OMEGA 0 +M_OMEGADIFF 0 +M_ETA 0 +M_ETADIFF 0 +M_DPDETA 1 +M_SMOOTH 0 +M_FORMAT GRIB1 +M_ADDPAR 186/187/188/235/139/39 +PREFIX EH +ECSTORAGE 1 +ECTRANS 0 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILOPS ${USER} +MAILFAIL ${USER} +EOF diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OD b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OD new file mode 100644 index 0000000..f82261e --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OD @@ -0,0 +1,35 @@ +DAY1 20151007 +DAY2 20151007 +DTIME 3 +M_TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC +M_TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12 +M_STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11 +M_CLASS OD +M_STREAM OPER +M_NUMBER OFF +M_EXPVER 1 +M_GRID 1000 +M_LEFT -10000 +M_LOWER 30000 +M_UPPER 60000 +M_RIGHT 30000 +M_LEVEL 137 +M_LEVELIST 130/to/137 +M_RESOL 399 +M_GAUSS 0 +M_ACCURACY 16 +M_OMEGA 0 +M_OMEGADIFF 0 +M_ETA 1 +M_ETADIFF 0 +M_DPDETA 1 +M_SMOOTH 0 +M_FORMAT GRIB1 +M_ADDPAR 186/187/188/235/139/39 +PREFIX EO +ECSTORAGE 0 +ECTRANS 1 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILOPS ${USER} +MAILFAIL ${USER} +EOF diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OPS_V4.temp b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OPS_V4.temp new file mode 100644 index 0000000..adf002a --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OPS_V4.temp @@ -0,0 +1,17 @@ +M_GRID 50 +M_LEFT -17950 +M_RESOL 399 +M_GAUSS 0 +M_ETA 1 +M_EXPVER 1 +M_LEVEL 137 +M_LEVELIST 1/to/137 +M_LEVMAX=137 +M_FORMAT GRIB1 +M_ADDPAR /186/187/188/235/139/39 +ECSTORAGE 1 +ECTRANS 1 +ECFSDIR ectmp:/${USER}/ecops +MAILOPS ${USER} +MAILFAIL ${USER} + diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OPS_V6.0 b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OPS_V6.0 new file mode 100644 index 0000000..973e8e3 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OPS_V6.0 @@ -0,0 +1,29 @@ +M_TYPE AN FC FC FC FC FC FC FC FC FC FC FC AN FC FC FC FC FC FC FC FC FC FC FC FC +M_TIME 00 00 00 00 00 00 00 00 00 00 00 00 12 12 12 12 12 12 12 12 12 12 12 12 12 +M_STEP 00 01 02 03 04 05 06 07 08 09 10 11 00 01 02 03 04 05 06 07 08 09 10 11 12 +DTIME 3 +PREFIX EN +M_UPPER 90000 +M_LOWER -90000 +M_LEFT -179000 +M_RIGHT 180000 +M_CLASS OD +M_STREAM OPER +M_NUMBER OFF +M_GRID 1000 +M_RESOL 255 +M_SMOOTH 0 +M_GAUSS 0 +M_ETA 1 +CWC 1 +M_ETAPAR 77 +M_DPDETA 1 +M_LEVEL 137 +M_LEVELIST 136/to/137 +M_ADDPAR /186/187/188/235/139/39 +M_FORMAT GRIB2 +ECSTORAGE 0 +ECTRANS 1 +ECFSDIR ectmp:/${USER}/ecops +MAILOPS ${USER} +MAILFAIL ${USER} diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OPS_V6.0_4V.temp b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OPS_V6.0_4V.temp new file mode 100644 index 0000000..02083f6 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_OPS_V6.0_4V.temp @@ -0,0 +1,28 @@ +M_TYPE AN FC FC FC FC FC AN FC FC 4V FC FC 4V FC FC FC FC FC AN FC FC 4V FC FC 4V +M_TIME 00 00 00 00 00 00 06 00 00 09 00 00 09 12 12 12 12 12 18 12 12 21 12 12 21 +M_STEP 00 01 02 03 04 05 00 07 08 00 10 11 03 01 02 03 04 05 00 07 08 00 10 11 03 +DTIME 1 +PREFIX EN +M_UPPER 90000 +M_LOWER -90000 +M_LEFT -179000 +M_RIGHT 180000 +M_CLASS OD +M_STREAM OPER +M_NUMBER OFF +M_GRID 1000 +M_RESOL 255 +M_SMOOTH 0 +M_GAUSS 1 +M_ETA 0 +M_ETAPAR 77 +M_DPDETA 1 +M_LEVEL 137 +M_LEVELIST 136/to/137 +M_ADDPAR 186/187/188/235/139/39 +M_FORMAT GRIB1 +ECSTORAGE 1 +ECTRANS 1 +ECFSDIR ectmp:/${USER}/ecops +MAILOPS ${USER} +MAILFAIL ${USER} diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_PF.temp b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_PF.temp new file mode 100644 index 0000000..8eb9cb5 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/run/control/CONTROL_PF.temp @@ -0,0 +1,38 @@ +DAY1 +DAY2 +DTIME 3 +MAXSTEP 36 +TYPE PF PF +TIME 12 12 +STEP 00 03 +CLASS OD +STREAM ENFO +NUMBER 0/to/9 +EXPVER 1 +GRID 1000 +LEFT -179000 +LOWER -90000 +UPPER 90000 +RIGHT 180000 +LEVEL 62 +LEVELIST 60-62 +RESOL 159 +GAUSS 1 +ACCURACY 16 +OMEGA 0 +OMEGADIFF 0 +ETA 0 +ETADIFF 0 +DPDETA 1 +SMOOTH 0 +FORMAT GRIB1 +ADDPAR /186/187/188/235/139/39 +PREFIX EE +ECSTORAGE 1 +ECTRANS 1 +ECFSDIR ectmp:/${USER}/econdemand/ +MAILOPS ${USER} +MAILFAIL ${USER} +FLEXPARTDIR ${HOME}/flex_extract_v7.1/flexpart_code +GRIB2FLEXPART grib2flexpart +EOF diff --git a/python/pythontest/TestInstallTar/test_untar/src/Makefile.CRAY b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/Makefile.CRAY similarity index 100% rename from python/pythontest/TestInstallTar/test_untar/src/Makefile.CRAY rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/Makefile.CRAY diff --git a/python/pythontest/TestInstallTar/test_untar/src/Makefile.gfortran b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/Makefile.gfortran similarity index 100% rename from python/pythontest/TestInstallTar/test_untar/src/Makefile.gfortran rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/Makefile.gfortran diff --git a/python/pythontest/TestInstallTar/test_untar/src/Makefile.ifort b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/Makefile.ifort similarity index 100% rename from python/pythontest/TestInstallTar/test_untar/src/Makefile.ifort rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/Makefile.ifort diff --git a/python/pythontest/TestInstallTar/test_untar/src/Makefile.local.gfortran b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/Makefile.local.gfortran similarity index 100% rename from python/pythontest/TestInstallTar/test_untar/src/Makefile.local.gfortran rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/Makefile.local.gfortran diff --git a/python/pythontest/TestInstallTar/test_untar/src/Makefile.local.ifort b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/Makefile.local.ifort similarity index 100% rename from python/pythontest/TestInstallTar/test_untar/src/Makefile.local.ifort rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/Makefile.local.ifort diff --git a/python/pythontest/TestInstallTar/test_untar/src/Makefile.new b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/Makefile.new similarity index 100% rename from python/pythontest/TestInstallTar/test_untar/src/Makefile.new rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/Makefile.new diff --git a/python/pythontest/TestInstallTar/test_untar/src/ftrafo.f b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/ftrafo.f similarity index 100% rename from python/pythontest/TestInstallTar/test_untar/src/ftrafo.f rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/ftrafo.f diff --git a/python/pythontest/TestInstallTar/test_untar/src/grphreal.f b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/grphreal.f similarity index 100% rename from python/pythontest/TestInstallTar/test_untar/src/grphreal.f rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/grphreal.f diff --git a/python/pythontest/TestInstallTar/test_untar/src/jparams.h b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/jparams.h similarity index 100% rename from python/pythontest/TestInstallTar/test_untar/src/jparams.h rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/jparams.h diff --git a/python/pythontest/TestInstallTar/test_untar/src/phgrreal.f b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/phgrreal.f similarity index 100% rename from python/pythontest/TestInstallTar/test_untar/src/phgrreal.f rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/phgrreal.f diff --git a/python/pythontest/TestInstallTar/test_untar/src/posnam.f b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/posnam.f similarity index 100% rename from python/pythontest/TestInstallTar/test_untar/src/posnam.f rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/posnam.f diff --git a/python/pythontest/TestInstallTar/test_untar/src/preconvert.f90 b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/preconvert.f90 similarity index 100% rename from python/pythontest/TestInstallTar/test_untar/src/preconvert.f90 rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/preconvert.f90 diff --git a/python/pythontest/TestInstallTar/test_untar/src/rwGRIB2.f90 b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/rwGRIB2.f90 similarity index 100% rename from python/pythontest/TestInstallTar/test_untar/src/rwGRIB2.f90 rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/fortran/rwGRIB2.f90 diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/__init__.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/__init__.py new file mode 100644 index 0000000..4609bf2 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/__init__.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +#******************************************************************************* +# @Author: Anne Philipp (University of Vienna) +# +# @Date: September 2018 +# +# @License: +# (C) Copyright 2015-2018. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# +#******************************************************************************* diff --git a/python/_config.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/_config.py similarity index 60% rename from python/_config.py rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/_config.py index 0270d97..e25aaa3 100644 --- a/python/_config.py +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/_config.py @@ -31,7 +31,6 @@ _VERSION_STR = '7.1' # FILENAMES # ------------------------------------------------------------------------------ -FLEXEXTRACT_DIRNAME = 'flex_extract_v' + _VERSION_STR FILE_MARS_REQUESTS = 'mars_requests.dat' FORTRAN_EXECUTABLE = 'CONVERT2' FILE_USER_ENVVARS = 'ECMWF_ENV' @@ -43,39 +42,37 @@ FILE_JOB_OD = 'job.ksh' FILE_JOB_OP = 'jopoper.ksh' FILE_NAMELIST = 'fort.4' FILE_GRIB_INDEX = 'date_time_stepRange.idx' +FILE_GRIBTABLE = 'ecmwf_grib1_table_128' # ------------------------------------------------------------------------------ -# PATHES +# DIRECTORY NAMES # ------------------------------------------------------------------------------ -# path to the flex_extract directory -PATH_FLEXEXTRACT_DIR = os.path.normpath(os.path.dirname(os.path.abspath( - inspect.getfile(inspect.currentframe()))) + '/../') +FLEXEXTRACT_DIRNAME = 'flex_extract_v' + _VERSION_STR +INPUT_DIRNAME_DEFAULT = 'workspace' + +# ------------------------------------------------------------------------------ +# PATHES +# ------------------------------------------------------------------------------ # path to the local python source files +# first thing to get because the submitted python script starts in here PATH_LOCAL_PYTHON = os.path.dirname(os.path.abspath( inspect.getfile(inspect.currentframe()))) -PATH_RELATIVE_PYTHON = os.path.relpath(PATH_LOCAL_PYTHON, PATH_FLEXEXTRACT_DIR) # add path to pythonpath if PATH_LOCAL_PYTHON not in sys.path: sys.path.append(PATH_LOCAL_PYTHON) - -# path to the templates -PATH_TEMPLATES = os.path.join(PATH_FLEXEXTRACT_DIR, '_templates') -PATH_RELATIVE_TEMPLATES = os.path.relpath(PATH_TEMPLATES, PATH_FLEXEXTRACT_DIR) - -# path to the environment parameter file -PATH_ECMWF_ENV = os.path.join(PATH_LOCAL_PYTHON, FILE_USER_ENVVARS) -PATH_RELATIVE_ECMWF_ENV = os.path.relpath(PATH_ECMWF_ENV, PATH_FLEXEXTRACT_DIR) - -# path to gribtable -PATH_GRIBTABLE = os.path.join(PATH_TEMPLATES, 'ecmwf_grib1_table_128') - -# path to run directory +PATH_FLEXEXTRACT_DIR = os.path.normpath(os.path.dirname(os.path.abspath( + inspect.getfile(inspect.currentframe()))) + '/../../') PATH_RUN_DIR = os.path.join(PATH_FLEXEXTRACT_DIR, 'run') -PATH_RELATIVE_RUN_DIR = os.path.relpath(PATH_RUN_DIR, PATH_FLEXEXTRACT_DIR) - -# path to directory where all control files are stored +PATH_SOURCES = os.path.join(PATH_FLEXEXTRACT_DIR, 'source') +PATH_TEMPLATES = os.path.join(PATH_FLEXEXTRACT_DIR, 'templates') +PATH_ECMWF_ENV = os.path.join(PATH_RUN_DIR, FILE_USER_ENVVARS) +PATH_GRIBTABLE = os.path.join(PATH_TEMPLATES, FILE_GRIBTABLE) +PATH_JOBSCRIPTS = os.path.join(PATH_RUN_DIR, 'jobscripts') +PATH_FORTRAN_SRC = os.path.join(PATH_SOURCES, 'fortran') +PATH_TEST_DIR = os.path.join(PATH_SOURCES, 'pythontest') +PATH_INPUT_DIR = os.path.join(PATH_RUN_DIR, INPUT_DIRNAME_DEFAULT) if os.getenv('CONTROL') and '/' in os.getenv('CONTROL'): # this is only needed if remote version with job script is used! # because job is directly submitted from SCRATCH and because the @@ -83,16 +80,15 @@ if os.getenv('CONTROL') and '/' in os.getenv('CONTROL'): PATH_CONTROLFILES = os.getenv('CONTROL') else: PATH_CONTROLFILES = os.path.join(PATH_RUN_DIR, 'control') - PATH_RELATIVE_CONTROLFILES = os.path.relpath(PATH_CONTROLFILES, PATH_FLEXEXTRACT_DIR) - -# path to directory where all job scripts are stored -PATH_JOBSCRIPTS = os.path.join(PATH_RUN_DIR, 'jobscripts') -PATH_RELATIVE_JOBSCRIPTS = os.path.relpath(PATH_JOBSCRIPTS, PATH_FLEXEXTRACT_DIR) - -# path to the fortran executable and the source code -PATH_FORTRAN_SRC = os.path.join(PATH_FLEXEXTRACT_DIR, 'src') -PATH_RELATIVE_FORTRAN_SRC = os.path.relpath(PATH_FORTRAN_SRC, PATH_FLEXEXTRACT_DIR) - -# path to the python testing directory -PATH_TEST_DIR = os.path.join(PATH_LOCAL_PYTHON, 'pythontest') - +# +# ------------------------------------------------------------------------------ +# +# for making the installation tar ball the relative pathes to the +# flex_extract root directory are needed +PATH_REL_PYTHON = os.path.relpath(PATH_LOCAL_PYTHON, PATH_FLEXEXTRACT_DIR) +PATH_REL_CONTROLFILES = os.path.relpath(PATH_CONTROLFILES, PATH_FLEXEXTRACT_DIR) +PATH_REL_TEMPLATES = os.path.relpath(PATH_TEMPLATES, PATH_FLEXEXTRACT_DIR) +PATH_REL_ECMWF_ENV = os.path.relpath(PATH_ECMWF_ENV, PATH_FLEXEXTRACT_DIR) +PATH_REL_RUN_DIR = os.path.relpath(PATH_RUN_DIR, PATH_FLEXEXTRACT_DIR) +PATH_REL_JOBSCRIPTS = os.path.relpath(PATH_JOBSCRIPTS, PATH_FLEXEXTRACT_DIR) +PATH_REL_FORTRAN_SRC = os.path.relpath(PATH_FORTRAN_SRC, PATH_FLEXEXTRACT_DIR) diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/ControlFile.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/ControlFile.py similarity index 82% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/python/ControlFile.py rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/ControlFile.py index 59a4752..97e6989 100644 --- a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/ControlFile.py +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/ControlFile.py @@ -112,7 +112,7 @@ class ControlFile(object): self.marsclass = None self.stream = None self.number = 'OFF' - self.expver = None + self.expver = '1' self.grid = None self.area = '' self.left = None @@ -142,12 +142,12 @@ class ControlFile(object): self.grib2flexpart = 0 self.ecstorage = 0 self.ectrans = 0 - self.inputdir = '../work' + self.inputdir = _config.PATH_INPUT_DIR self.outputdir = self.inputdir - self.ecmwfdatadir = None - self.exedir = None + self.ecmwfdatadir = _config.PATH_FLEXEXTRACT_DIR + self.exedir = _config.PATH_FORTRAN_SRC self.flexpart_root_scripts = None - self.makefile = None + self.makefile = 'Makefile.gfortran' self.destination = None self.gateway = None self.ecuid = None @@ -156,6 +156,10 @@ class ControlFile(object): self.debug = 0 self.request = 0 + self.logicals = ['gauss', 'omega', 'omegadiff', 'eta', 'etadiff', + 'dpdeta', 'cwc', 'wrf', 'grib2flexpart', 'ecstorage', + 'ectrans', 'debug', 'request'] + self.__read_controlfile__() return @@ -172,10 +176,11 @@ class ControlFile(object): @Return: <nothing> ''' - from tools import my_error + from mods.tools import my_error # read whole CONTROL file - with open(self.controlfile) as f: + with open(os.path.join(_config.PATH_CONTROLFILES, + self.controlfile)) as f: fdata = f.read().split('\n') # go through every line and store parameter @@ -225,13 +230,6 @@ class ControlFile(object): else: pass - # script directory - self.ecmwfdatadir = os.path.dirname(os.path.abspath(inspect.getfile( - inspect.currentframe()))) + '/../' - - # Fortran source directory - self.exedir = self.ecmwfdatadir + 'src/' - return def __str__(self): @@ -313,7 +311,7 @@ class ControlFile(object): return - def check_conditions(self): + def check_conditions(self, queue): ''' @Description: Checks a couple of necessary attributes and conditions, @@ -324,19 +322,24 @@ class ControlFile(object): self: instance of ControlFile class Description see class documentation. + queue: string + Name of the queue if submitted to the ECMWF servers. + Used to check if ecuid, ecgid, gateway and destination + are set correctly and are not empty. + @Return: <nothing> ''' - from tools import my_error + from mods.tools import my_error import numpy as np # check for having at least a starting date # otherwise program is not allowed to run if self.start_date is None: - print 'start_date specified neither in command line nor ' + \ - 'in CONTROL file ' + self.controlfile - print 'Try "' + sys.argv[0].split('/')[-1] + \ - ' -h" to print usage information' + print('start_date specified neither in command line nor \ + in CONTROL file ' + self.controlfile) + print('Try "' + sys.argv[0].split('/')[-1] + + ' -h" to print usage information') sys.exit(1) # retrieve just one day if end_date isn't set @@ -344,41 +347,42 @@ class ControlFile(object): self.end_date = self.start_date # assure consistency of levelist and level - if self.levelist is None: - if self.level is None: - print 'Warning: neither levelist nor level ' + \ - 'specified in CONTROL file' - sys.exit(1) - else: - self.levelist = '1/to/' + self.level + if self.levelist is None and self.level is None: + print('Warning: neither levelist nor level \ + specified in CONTROL file') + sys.exit(1) + elif self.levelist is None and self.level: + self.levelist = '1/to/' + self.level + elif (self.levelist and self.level is None) or \ + (self.levelist[-1] != self.level[-1]): + self.level = self.levelist.split('/')[-1] else: - if 'to' in self.levelist.lower(): - self.level = self.levelist.split('/')[2] - else: - self.level = self.levelist.split('/')[-1] + pass - # if area was provided at command line - # decompse area into its 4 components + # if area was provided (only from commandline) + # decompose area into its 4 components if self.area: - afloat = '.' in self.area - l = self.area.split('/') - if afloat: - for i, item in enumerate(l): - item = str(int(float(item) * 1000)) - self.upper, self.left, self.lower, self.right = l - - # prepare step for correct usage + components = self.area.split('/') + # convert float to integer coordinates + if '.' in self.area: + components = [str(int(float(item) * 1000)) + for i, item in enumerate(components)] + self.upper, self.left, self.lower, self.right = components + + # prepare step list if "/" signs are found if '/' in self.step: - l = self.step.split('/') - if 'to' in self.step.lower(): - if 'by' in self.step.lower(): - ilist = np.arange(int(l[0]), int(l[2]) + 1, int(l[4])) - self.step = ['{:0>3}'.format(i) for i in ilist] - else: - my_error(self.mailfail, self.step + ':\n' + - 'if "to" is used, please use "by" as well') + steps = self.step.split('/') + if 'to' in self.step.lower() and 'by' in self.step.lower(): + ilist = np.arange(int(steps[0]), + int(steps[2]) + 1, + int(steps[4])) + self.step = ['{:0>3}'.format(i) for i in ilist] + elif 'to' in self.step.lower() and 'by' not in self.step.lower(): + my_error(self.mailfail, self.step + ':\n' + + 'if "to" is used in steps parameter, \ + please use "by" as well') else: - self.step = l + self.step = steps # if maxstep wasn't provided # search for it in the "step" parameter @@ -410,27 +414,24 @@ class ControlFile(object): else: self.mailops = [self.mailops] - if not self.gateway or not self.destination or \ + if queue in ['ecgate', 'cca'] and \ + not self.gateway or not self.destination or \ not self.ecuid or not self.ecgid: - print '\nEnvironment variables GATWAY, DESTINATION, ECUID and ' + \ - 'ECGID were not set properly!' - print 'Please check for excistence of file "ECMWF_ENV" in the ' + \ - 'python directory!' + print('\nEnvironment variables GATEWAY, DESTINATION, ECUID and \ + ECGID were not set properly!') + print('Please check for existence of file "ECMWF_ENV" in the \ + python directory!') sys.exit(1) if self.request != 0: - marsfile = os.path.join(_config.PATH_RUN_DIR + os.path.sep + + marsfile = os.path.join(self.inputdir, _config.FILE_MARS_REQUESTS) if os.path.isfile(marsfile): os.remove(marsfile) - # check logical variables for data type + # check all logical variables for data type # if its a string change to integer - logicals = ['gauss', 'omega', 'omegadiff', 'eta', 'etadiff', - 'dpdeta', 'cwc', 'wrf', 'grib2flexpart', 'ecstorage', - 'ectrans', 'debug', 'request'] - - for var in logicals: + for var in self.logicals: if not isinstance(getattr(self, var), int): setattr(self, var, int(getattr(self, var))) @@ -480,10 +481,7 @@ class ControlFile(object): self.flexpart_root_scripts = self.flexpart_root_scripts else: # local if not self.flexpart_root_scripts: - self.flexpart_root_scripts = '../' - - if not self.makefile: - self.makefile = 'Makefile.gfortran' + self.flexpart_root_scripts = _config.PATH_FLEXEXTRACT_DIR return diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/EcFlexpart.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/EcFlexpart.py similarity index 90% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/python/EcFlexpart.py rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/EcFlexpart.py index 57b2da6..6f4fbae 100644 --- a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/EcFlexpart.py +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/EcFlexpart.py @@ -60,31 +60,12 @@ # - deacc_fluxes # # @Class Attributes: -# - dtime -# - basetime -# - server -# - marsclass -# - stream -# - resol -# - accuracy -# - number -# - expver -# - glevelist -# - area -# - grid -# - level -# - levelist -# - types -# - dates -# - area -# - gaussian -# - params -# - inputdir -# - outputfilelist +# +# TODO # #******************************************************************************* #pylint: disable=unsupported-assignment-operation -# this is disabled because its an error in pylint for this specific case +# this is disabled because for this specific case its an error in pylint #pylint: disable=consider-using-enumerate # this is not useful in this case # ------------------------------------------------------------------------------ @@ -103,9 +84,9 @@ from gribapi import grib_set, grib_index_select, grib_new_from_index, grib_get,\ # software specific classes and modules from flex_extract import _config from GribTools import GribTools -from tools import init128, to_param_id, silent_remove, product, my_error +from mods.tools import init128, to_param_id, silent_remove, product, my_error from MarsRetrieval import MarsRetrieval -import disaggregation +import mods.disaggregation # ------------------------------------------------------------------------------ # CLASS @@ -204,12 +185,8 @@ class EcFlexpart(object): self.resol = c.resol self.accuracy = c.accuracy self.level = c.level - - if c.levelist: - self.levelist = c.levelist - else: - self.levelist = '1/to/' + c.level - + self.expver = c.expver + self.levelist = c.levelist # for gaussian grid retrieval self.glevelist = '1/to/' + c.level @@ -218,16 +195,6 @@ class EcFlexpart(object): else: self.gaussian = '' - if hasattr(c, 'expver') and c.expver: - self.expver = c.expver - else: - self.expver = '1' - - if hasattr(c, 'number') and c.number: - self.number = c.number - else: - self.number = '0' - if 'N' in c.grid: # Gaussian output grid self.grid = c.grid self.area = 'G' @@ -250,7 +217,6 @@ class EcFlexpart(object): # 3) Calculation/Retrieval of omega # 4) Download also data for WRF - # Different grids need different retrievals # SH = Spherical Harmonics, GG = Gaussian Grid, # OG = Output Grid, ML = MultiLevel, SL = SingleLevel @@ -274,34 +240,37 @@ class EcFlexpart(object): self.params['OG__ML'] = ['T/Q', 'ML', self.levelist, self.grid] - if c.gauss == '0' and c.eta == '1': + #if c.gauss == '0' and c.eta == '1': + if not c.gauss and c.eta: # the simplest case self.params['OG__ML'][0] += '/U/V/77' - elif c.gauss == '0' and c.eta == '0': + #elif c.gauss == '0' and c.eta == '0': + elif not c.gauss and not c.eta: # this is not recommended (inaccurate) self.params['OG__ML'][0] += '/U/V' - elif c.gauss == '1' and c.eta == '0': + #elif c.gauss == '1' and c.eta == '0': + elif c.gauss and not c.eta: # this is needed for data before 2008, or for reanalysis data self.params['GG__SL'] = ['Q', 'ML', '1', \ '{}'.format((int(self.resol) + 1) / 2)] self.params['SH__ML'] = ['U/V/D', 'ML', self.glevelist, 'OFF'] else: - print('Warning: This is a very costly parameter combination, ' - 'use only for debugging!') + print('Warning: This is a very costly parameter combination, \ + use only for debugging!') self.params['GG__SL'] = ['Q', 'ML', '1', \ '{}'.format((int(self.resol) + 1) / 2)] self.params['GG__ML'] = ['U/V/D/77', 'ML', self.glevelist, \ '{}'.format((int(self.resol) + 1) / 2)] - if hasattr(c, 'omega') and c.omega == '1': + if c.omega: self.params['OG__ML'][0] += '/W' # add cloud water content if necessary - if hasattr(c, 'cwc') and c.cwc == '1': + if c.cwc: self.params['OG__ML'][0] += '/CLWC/CIWC' # add vorticity and geopotential height for WRF if necessary - if hasattr(c, 'wrf') and c.wrf == '1': + if c.wrf: self.params['OG__ML'][0] += '/Z/VO' if '/D' not in self.params['OG__ML'][0]: self.params['OG__ML'][0] += '/D' @@ -438,7 +407,7 @@ class EcFlexpart(object): if pk == 'OG__SL': pass if pk == 'OG_OROLSM__SL': - if oro is False: + if not oro: mfstream = 'OPER' mftype = 'AN' mftime = '00' @@ -458,7 +427,7 @@ class EcFlexpart(object): gaussian = self.gaussian # ------ on demand path -------------------------------------------------- - if self.basetime is None: + if not self.basetime: MR = MarsRetrieval(self.server, marsclass=self.marsclass, stream=mfstream, @@ -482,13 +451,13 @@ class EcFlexpart(object): MR.display_info() MR.data_retrieve() elif request == 1: - MR.print_info() + MR.print_info(self.inputdir) elif request == 2: - MR.print_info() + MR.print_info(self.inputdir) MR.display_info() MR.data_retrieve() else: - print 'Failure' + print('Failure') # ------ operational path ------------------------------------------------ else: # check if mars job requests fields beyond basetime. @@ -716,20 +685,20 @@ class EcFlexpart(object): ''' - print '\n\nPostprocessing:\n Format: {}\n'.format(c.format) + print('\n\nPostprocessing:\n Format: {}\n'.format(c.format)) - if c.ecapi is False: + if not c.ecapi: print('ecstorage: {}\n ecfsdir: {}\n'. format(c.ecstorage, c.ecfsdir)) - if not hasattr(c, 'gateway'): - c.gateway = os.getenv('GATEWAY') - if not hasattr(c, 'destination'): - c.destination = os.getenv('DESTINATION') + #if not hasattr(c, 'gateway'): + # c.gateway = os.getenv('GATEWAY') + #if not hasattr(c, 'destination'): + # c.destination = os.getenv('DESTINATION') print('ectrans: {}\n gateway: {}\n destination: {}\n ' .format(c.ectrans, c.gateway, c.destination)) - print 'Output filelist: \n' - print self.outputfilelist + print('Output filelist: \n') + print(self.outputfilelist) if c.format.lower() == 'grib2': for ofile in self.outputfilelist: @@ -738,14 +707,14 @@ class EcFlexpart(object): ofile, ofile + '_2']) p = subprocess.check_call(['mv', ofile + '_2', ofile]) - if int(c.ectrans) == 1 and c.ecapi is False: + if c.ectrans and not c.ecapi: for ofile in self.outputfilelist: p = subprocess.check_call(['ectrans', '-overwrite', '-gateway', c.gateway, '-remote', c.destination, '-source', ofile]) #print('ectrans:', p) - if int(c.ecstorage) == 1 and c.ecapi is False: + if c.ecstorage and not c.ecapi: for ofile in self.outputfilelist: p = subprocess.check_call(['ecp', '-o', ofile, os.path.expandvars(c.ecfsdir)]) @@ -756,7 +725,7 @@ class EcFlexpart(object): # prepare environment for the grib2flexpart run # to convert grib to flexpart binary - if c.grib2flexpart == '1': + if c.grib2flexpart: # generate AVAILABLE file # Example of AVAILABLE file data: @@ -872,7 +841,7 @@ class EcFlexpart(object): table128) index_keys = ["date", "time", "step"] - indexfile = c.inputdir + "/date_time_stepRange.idx" + indexfile = os.path.join(c.inputdir, _config.FILE_GRIB_INDEX) silent_remove(indexfile) grib = GribTools(inputfiles.files) # creates new index file @@ -882,7 +851,7 @@ class EcFlexpart(object): index_vals = [] for key in index_keys: index_vals.append(grib_index_get(iid, key)) - print index_vals[-1] + print(index_vals[-1]) # index_vals looks for example like: # index_vals[0]: ('20171106', '20171107', '20171108') ; date # index_vals[1]: ('0', '1200', '1800', '600') ; time @@ -892,9 +861,13 @@ class EcFlexpart(object): '17':None, '19':None, '21':None, '22':None, '20':None} for prod in product(*index_vals): + # e.g. prod = ('20170505', '0', '12') + # ( date ,time, step) + # per date e.g. time = 0, 1200 + # per time e.g. step = 3, 6, 9, 12 # flag for Fortran program CONVERT2 and file merging convertFlag = False - print 'current prod: ', prod + print('current prod: ', prod) # e.g. prod = ('20170505', '0', '12') # ( date ,time, step) # per date e.g. time = 0, 600, 1200, 1800 @@ -916,8 +889,9 @@ class EcFlexpart(object): # remove old fort.* files and open new ones # they are just valid for a single product for k, f in fdict.iteritems(): - silent_remove(c.inputdir + "/fort." + k) - fdict[k] = open(c.inputdir + '/fort.' + k, 'w') + fortfile = os.path.join(c.inputdir, 'fort.' + k) + silent_remove(fortfile) + fdict[k] = open(fortfile, 'w') cdate = str(grib_get(gid, 'date')) time = grib_get(gid, 'time') @@ -945,23 +919,20 @@ class EcFlexpart(object): if timestamp < slimit or timestamp > elimit: continue + else: + pass try: - if c.wrf == '1': - if 'olddate' not in locals(): - fwrf = open(c.outputdir + '/WRF' + cdate + - '.{:0>2}'.format(time) + '.000.grb2', 'w') + if c.wrf: + if 'olddate' not in locals() or cdate != olddate: + fwrf = open(os.path.join(c.outputdir, + 'WRF' + cdate + '.{:0>2}'.format(time) + + '.000.grb2'), 'w') olddate = cdate[:] - else: - if cdate != olddate: - fwrf = open(c.outputdir + '/WRF' + cdate + - '.{:0>2}'.format(time) + '.000.grb2', - 'w') - olddate = cdate[:] except AttributeError: pass - # helper variable to remember which fields are already used. + # helper variable to remember which fields were already used. savedfields = [] while 1: if gid is None: @@ -972,7 +943,7 @@ class EcFlexpart(object): if paramId == 133 and gridtype == 'reduced_gg': # Specific humidity (Q.grb) is used as a template only # so we need the first we "meet" - with open(c.inputdir + '/fort.18', 'w') as fout: + with open(os.path.join(c.inputdir, 'fort.18'), 'w') as fout: grib_write(gid, fout) elif paramId == 131 or paramId == 132: grib_write(gid, fdict['10']) @@ -985,7 +956,7 @@ class EcFlexpart(object): elif paramId == 155 and gridtype == 'sh': grib_write(gid, fdict['13']) elif paramId in [129, 138, 155] and levtype == 'hybrid' \ - and c.wrf == '1': + and c.wrf: pass elif paramId == 246 or paramId == 247: # cloud liquid water and ice @@ -1005,16 +976,17 @@ class EcFlexpart(object): grib_write(gid, fdict['16']) savedfields.append(paramId) else: - print 'duplicate ' + str(paramId) + ' not written' + print('duplicate ' + str(paramId) + ' not written') try: - if c.wrf == '1': - if levtype == 'hybrid': # model layer - if paramId in [129, 130, 131, 132, 133, 138, 155]: - grib_write(gid, fwrf) - else: # sfc layer - if paramId in wrfpars: - grib_write(gid, fwrf) + if c.wrf: + # model layer + if levtype == 'hybrid' and \ + paramId in [129, 130, 131, 132, 133, 138, 155]: + grib_write(gid, fwrf) + # sfc layer + elif paramId in wrfpars: + grib_write(gid, fwrf) except AttributeError: pass @@ -1028,29 +1000,28 @@ class EcFlexpart(object): if convertFlag: pwd = os.getcwd() os.chdir(c.inputdir) - if os.stat('fort.21').st_size == 0 and int(c.eta) == 1: - print 'Parameter 77 (etadot) is missing, most likely it is \ - not available for this type or date/time\n' - print 'Check parameters CLASS, TYPE, STREAM, START_DATE\n' + if os.stat('fort.21').st_size == 0 and c.eta: + print('Parameter 77 (etadot) is missing, most likely it is \ + not available for this type or date/time\n') + print('Check parameters CLASS, TYPE, STREAM, START_DATE\n') my_error(c.mailfail, 'fort.21 is empty while parameter eta \ is set to 1 in CONTROL file') # create the corresponding output file fort.15 # (generated by CONVERT2) + fort.16 (paramId 167 and 168) - p = subprocess.check_call( - [os.path.expandvars(os.path.expanduser(c.exedir)) + - '/CONVERT2'], shell=True) + p = subprocess.check_call([os.path.join(c.exedir, 'CONVERT2')], + shell=True) os.chdir(pwd) # create final output filename, e.g. EN13040500 (ENYYMMDDHH) - fnout = c.inputdir + '/' + c.prefix + fnout = os.path.join(c.inputdir, c.prefix) if c.maxstep > 12: suffix = cdate[2:8] + '.{:0>2}'.format(time/100) + \ '.{:0>3}'.format(step) else: suffix = cdateH[2:10] fnout += suffix - print "outputfile = " + fnout + print("outputfile = " + fnout) self.outputfilelist.append(fnout) # needed for final processing # create outputfile and copy all data from intermediate files @@ -1058,22 +1029,25 @@ class EcFlexpart(object): orolsm = os.path.basename(glob.glob( c.inputdir + '/OG_OROLSM__SL.*.' + c.ppid + '*')[0]) fluxfile = 'flux' + cdate[0:2] + suffix - if c.cwc != '1': + if not c.cwc: flist = ['fort.15', fluxfile, 'fort.16', orolsm] else: flist = ['fort.15', 'fort.22', fluxfile, 'fort.16', orolsm] with open(fnout, 'wb') as fout: for f in flist: - shutil.copyfileobj( - open(c.inputdir + '/' + f, 'rb'), fout) + shutil.copyfileobj(open(os.path.join(c.inputdir, f), + 'rb'), fout) - if c.omega == '1': - with open(c.outputdir + '/OMEGA', 'wb') as fout: + if c.omega: + with open(os.path.join(c.outputdir, 'OMEGA'), 'wb') as fout: shutil.copyfileobj( - open(c.inputdir + '/fort.25', 'rb'), fout) + open(os.path.join(c.inputdir, 'fort.25'), + 'rb'), fout) + else: + pass - if hasattr(c, 'wrf') and c.wrf == '1': + if c.wrf: fwrf.close() grib_index_release(iid) @@ -1116,7 +1090,7 @@ class EcFlexpart(object): table128 = init128(_config.PATH_GRIBTABLE) pars = to_param_id(self.params['OG_acc_SL'][0], table128) index_keys = ["date", "time", "step"] - indexfile = c.inputdir + "/date_time_stepRange.idx" + indexfile = os.path.join(c.inputdir, _config.FILE_GRIB_INDEX) silent_remove(indexfile) grib = GribTools(inputfiles.files) # creates new index file @@ -1126,7 +1100,7 @@ class EcFlexpart(object): index_vals = [] for key in index_keys: key_vals = grib_index_get(iid, key) - print key_vals + print(key_vals) # have to sort the steps for disaggregation, # therefore convert to int first if key == 'step': @@ -1147,17 +1121,22 @@ class EcFlexpart(object): svalsdict[str(p)] = [] stepsdict[str(p)] = [] - print 'maxstep: ', c.maxstep + print('maxstep: ', c.maxstep) for prod in product(*index_vals): # e.g. prod = ('20170505', '0', '12') # ( date ,time, step) # per date e.g. time = 0, 1200 # per time e.g. step = 3, 6, 9, 12 + print('current prod: ', prod) for i in range(len(index_keys)): grib_index_select(iid, index_keys[i], prod[i]) + # get first id from current product gid = grib_new_from_index(iid) + + # if there is data for this product combination + # prepare some date and time parameter before reading the data if gid is not None: cdate = grib_get(gid, 'date') time = grib_get(gid, 'time') @@ -1175,28 +1154,31 @@ class EcFlexpart(object): break if c.maxstep > 12: - fnout = c.inputdir + '/flux' + \ - sdate.strftime('%Y%m%d') + '.{:0>2}'.format(time/100) + \ - '.{:0>3}'.format(step-2*int(c.dtime)) - gnout = c.inputdir + '/flux' + \ - sdate.strftime('%Y%m%d') + '.{:0>2}'.format(time/100) + \ - '.{:0>3}'.format(step-int(c.dtime)) - hnout = c.inputdir + '/flux' + \ - sdate.strftime('%Y%m%d') + '.{:0>2}'.format(time/100) + \ - '.{:0>3}'.format(step) - g = open(gnout, 'w') - h = open(hnout, 'w') + fnout = os.path.join(c.inputdir, 'flux' + + sdate.strftime('%Y%m%d') + + '.{:0>2}'.format(time/100) + + '.{:0>3}'.format(step-2*int(c.dtime))) + gnout = os.path.join(c.inputdir, 'flux' + + sdate.strftime('%Y%m%d') + + '.{:0>2}'.format(time/100) + + '.{:0>3}'.format(step-int(c.dtime))) + hnout = os.path.join(c.inputdir, 'flux' + + sdate.strftime('%Y%m%d') + + '.{:0>2}'.format(time/100) + + '.{:0>3}'.format(step)) else: - fnout = c.inputdir + '/flux' + fdate.strftime('%Y%m%d%H') - gnout = c.inputdir + '/flux' + (fdate + - timedelta(hours=int(c.dtime)) - ).strftime('%Y%m%d%H') - hnout = c.inputdir + '/flux' + sdates.strftime('%Y%m%d%H') - g = open(gnout, 'w') - h = open(hnout, 'w') - - print "outputfile = " + fnout - f = open(fnout, 'w') + fnout = os.path.join(c.inputdir, 'flux' + + fdate.strftime('%Y%m%d%H')) + gnout = os.path.join(c.inputdir, 'flux' + + (fdate + timedelta(hours=int(c.dtime))). + strftime('%Y%m%d%H')) + hnout = os.path.join(c.inputdir, 'flux' + + sdates.strftime('%Y%m%d%H')) + + print("outputfile = " + fnout) + f_handle = open(fnout, 'w') + g_handle = open(gnout, 'w') + h_handle = open(hnout, 'w') # read message for message and store relevant data fields # data keywords are stored in pars @@ -1257,7 +1239,7 @@ class EcFlexpart(object): grib_set(gid, 'time', fdate.hour*100) grib_set(gid, 'date', fdate.year*10000 + fdate.month*100+fdate.day) - grib_write(gid, f) + grib_write(gid, f_handle) if c.basetime is not None: elimit = datetime.strptime(c.end_date + @@ -1284,7 +1266,7 @@ class EcFlexpart(object): grib_set(gid, 'date', truedatetime.year * 10000 + truedatetime.month * 100 + truedatetime.day) - grib_write(gid, h) + grib_write(gid, h_handle) #values = (svdp[1]+svdp[2])/2. if cparamId == '142' or cparamId == '143': @@ -1299,15 +1281,15 @@ class EcFlexpart(object): truedatetime.month * 100 + truedatetime.day) grib_set_values(gid, values) - grib_write(gid, g) + grib_write(gid, g_handle) grib_release(gid) gid = grib_new_from_index(iid) - f.close() - g.close() - h.close() + f_handle.close() + g_handle.close() + h_handle.close() grib_index_release(iid) diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/GribTools.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/GribTools.py similarity index 98% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/python/GribTools.py rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/GribTools.py index a68d1a5..7d375b1 100644 --- a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/GribTools.py +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/GribTools.py @@ -296,15 +296,15 @@ class GribTools(object): iid: integer Grib index id. ''' - print "... index will be done" + print("... index will be done") iid = None if os.path.exists(index_file): iid = grib_index_read(index_file) - print "Use existing index file: %s " % (index_file) + print("Use existing index file: %s " % (index_file)) else: for filename in self.filenames: - print "Inputfile: %s " % (filename) + print("Inputfile: %s " % (filename)) if iid is None: iid = grib_index_new_from_file(filename, index_keys) else: @@ -313,6 +313,6 @@ class GribTools(object): if iid is not None: grib_index_write(iid, index_file) - print '... index done' + print('... index done') return iid diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/MarsRetrieval.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/MarsRetrieval.py similarity index 95% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/python/MarsRetrieval.py rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/MarsRetrieval.py index fa4012c..bb86f2b 100644 --- a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/MarsRetrieval.py +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/MarsRetrieval.py @@ -310,7 +310,8 @@ class MarsRetrieval(object): def display_info(self): ''' @Description: - Prints all class attributes and their values. + Prints all class attributes and their values to the + standard output. @Input: self: instance of MarsRetrieval @@ -328,19 +329,32 @@ class MarsRetrieval(object): if item[0] in 'server': pass else: - print item[0] + ': ' + str(item[1]) + print(item[0] + ': ' + str(item[1])) return - def print_info(self): + def print_info(self, inputdir): ''' + @Description: + Prints all mars requests to an extra file for debugging and + information. + + @Input: + self: instance of MarsRetrieval + For description see class documentation. + + inputdir: string + The path where all data from the retrievals are stored. + + @Return: + <nothing> ''' # Get all class attributes and their values as a dictionary attrs = vars(self) # open a file to store all requests to - with open(os.path.join(_config.PATH_RUN_DIR + os.path.sep + + with open(os.path.join(inputdir, _config.FILE_MARS_REQUESTS), 'a') as f: f.write('mars\n') # iterate through all attributes and print them @@ -393,8 +407,8 @@ class MarsRetrieval(object): try: self.server.execute(s, target) except: - print('MARS Request failed, ' - 'have you already registered at apps.ecmwf.int?') + print('MARS Request failed, \ + have you already registered at apps.ecmwf.int?') raise IOError if os.stat(target).st_size == 0: print('MARS Request returned no data - please check request') @@ -406,7 +420,7 @@ class MarsRetrieval(object): stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1) pout = p.communicate(input=s)[0] - print pout.decode() + print(pout.decode()) if 'Some errors reported' in pout.decode(): print('MARS Request failed - please check request') diff --git a/python/pythontest/TestInstallTar/test_untar/python/UioFiles.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/UioFiles.py similarity index 76% rename from python/pythontest/TestInstallTar/test_untar/python/UioFiles.py rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/UioFiles.py index fe69953..e9eaf86 100644 --- a/python/pythontest/TestInstallTar/test_untar/python/UioFiles.py +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/UioFiles.py @@ -51,7 +51,7 @@ import fnmatch # software specific module from flex_extract #import profiling -from tools import silent_remove, get_list_as_string +from mods.tools import silent_remove, get_list_as_string # ------------------------------------------------------------------------------ # CLASS @@ -59,9 +59,9 @@ from tools import silent_remove, get_list_as_string class UioFiles(object): ''' - Class to manipulate files. At initialisation it has the attribute - pattern which stores a regular expression pattern for the files associated - with the instance of the class. + Class to manipulate files. At initialisation it has the pattern + which stores a regular expression pattern for the files, the path + to the files and the files already. ''' # -------------------------------------------------------------------------- # CLASS FUNCTIONS @@ -87,14 +87,14 @@ class UioFiles(object): self.path = path self.pattern = pattern - self.files = None + self.files = [] self.__list_files__(self.path) return #@profiling.timefn - def __list_files__(self, path, callid=0): + def __list_files__(self, path): ''' @Description: Lists all files in the directory with the matching @@ -107,35 +107,16 @@ class UioFiles(object): path: string Path to the files. - callid: integer - Id which tells the function if its the first call - or a recursive call. Default and first call is 0. - Everything different from 0 is ment to be a recursive case. - @Return: <nothing> ''' - - # initialize variable in first function call - if callid == 0: - self.files = [] - # Get the absolute path path = os.path.abspath(path) - # get the file list of the path if its not a directory and - # if it contains the pattern - self.files.extend([os.path.join(path, k) for k in os.listdir(path) - if fnmatch.fnmatch(k, self.pattern)]) - - # find possible sub-directories in the path - subdirs = [s for s in os.listdir(path) - if os.path.isdir(os.path.join(path, s))] - - # do recursive calls for sub-direcorties - if subdirs: - for subdir in subdirs: - self.__list_files__(os.path.join(path, subdir), callid=1) + # get all files in the dir and subdir as absolut path + for root, dirnames, filenames in os.walk(path): + for filename in fnmatch.filter(filenames, self.pattern): + self.files.append(os.path.join(root, filename)) return diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/__init__.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/__init__.py new file mode 100644 index 0000000..4609bf2 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/classes/__init__.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +#******************************************************************************* +# @Author: Anne Philipp (University of Vienna) +# +# @Date: September 2018 +# +# @License: +# (C) Copyright 2015-2018. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# +#******************************************************************************* diff --git a/python/pythontest/TestInstallTar/test_untar/python/install.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/install.py similarity index 82% rename from python/pythontest/TestInstallTar/test_untar/python/install.py rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/install.py index ba99427..4d5c972 100755 --- a/python/pythontest/TestInstallTar/test_untar/python/install.py +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/install.py @@ -11,6 +11,9 @@ # - applied PEP8 style guide # - added documentation # - moved install_args_and_control in here +# - splitted code in smaller functions +# - delete convert build files in here instead of compile job script +# - changed static path names to Variables from config file # # @License: # (C) Copyright 2015-2018. @@ -54,10 +57,9 @@ from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter # software specific classes and modules from flex_extract import _config -from ControlFile import ControlFile -from UioFiles import UioFiles -from tools import make_dir, put_file_to_ecserver, submit_job_to_ecserver - +from classes.ControlFile import ControlFile +from classes.UioFiles import UioFiles +from mods.tools import make_dir, put_file_to_ecserver, submit_job_to_ecserver # ------------------------------------------------------------------------------ # FUNCTIONS @@ -75,16 +77,17 @@ def main(): <nothing> ''' - os.chdir(_config.PATH_LOCAL_PYTHON) + #os.chdir(_config.PATH_LOCAL_PYTHON) + args = get_install_cmdline_arguments() try: c = ControlFile(args.controlfile) except IOError: - print 'Could not read CONTROL file "' + args.controlfile + '"' - print 'Either it does not exist or its syntax is wrong.' - print 'Try "' + sys.argv[0].split('/')[-1] + \ - ' -h" to print usage information' + print('Could not read CONTROL file "' + args.controlfile + '"') + print('Either it does not exist or its syntax is wrong.') + print('Try "' + sys.argv[0].split('/')[-1] + + ' -h" to print usage information') exit(1) c.assign_args_to_control(args) @@ -129,7 +132,7 @@ def get_install_cmdline_arguments(): default=None, help="FLEXPART root directory on ECMWF \ servers (to find grib2flexpart and COMMAND file)\n\ Normally flex_extract resides in the scripts directory \ - of the FLEXPART distribution, thus the:") + of the FLEXPART distribution.") # arguments for job submission to ECMWF, only needed by submit.py parser.add_argument("--job_template", dest='job_template', @@ -170,7 +173,7 @@ def install_via_gateway(c): ecd = _config.PATH_FLEXEXTRACT_DIR tarball_name = _config.FLEXEXTRACT_DIRNAME + '.tar' - tar_file = os.path.join(ecd + os.path.sep + tarball_name) + tar_file = os.path.join(ecd, tarball_name) target_dirname = _config.FLEXEXTRACT_DIRNAME fortran_executable = _config.FORTRAN_EXECUTABLE @@ -185,14 +188,13 @@ def install_via_gateway(c): mk_env_vars(c.ecuid, c.ecgid, c.gateway, c.destination) - mk_tarball(tar_file) + mk_tarball(tar_file, c.install_target) put_file_to_ecserver(ecd, tarball_name, c.install_target, c.ecuid, c.ecgid) submit_job_to_ecserver(c.install_target, - os.path.join(_config.PATH_JOBSCRIPTS + - os.path.sep + + os.path.join(_config.PATH_REL_JOBSCRIPTS, _config.FILE_INSTALL_COMPILEJOB)) print('job compilation script has been submitted to ecgate for ' + @@ -202,25 +204,24 @@ def install_via_gateway(c): 'the next few minutes!') else: #local - if not c.flexpart_root_scripts or c.flexpart_root_scripts == '../': - #install_dir = c.flexpart_root_scripts + if c.flexpart_root_scripts == _config.PATH_FLEXEXTRACT_DIR : print('WARNING: FLEXPART_ROOT_SCRIPTS has not been specified') - print('There will be only the compilation of the Fortran program' + - ' in ' + _config.PATH_FORTRAN_SRC) + print('flex_extract will be installed in here by compiling the ' + + 'Fortran source in ' + _config.PATH_FORTRAN_SRC) os.chdir(_config.PATH_FORTRAN_SRC) else: # creates the target working directory for flex_extract c.flexpart_root_scripts = os.path.expandvars(os.path.expanduser( c.flexpart_root_scripts)) if os.path.abspath(ecd) != os.path.abspath(c.flexpart_root_scripts): - mk_tarball(tar_file) - make_dir(os.path.join(c.flexpart_root_scripts + os.path.sep + + mk_tarball(tar_file, c.install_target) + make_dir(os.path.join(c.flexpart_root_scripts, target_dirname)) - os.chdir(os.path.join(c.flexpart_root_scripts + os.path.sep + + os.chdir(os.path.join(c.flexpart_root_scripts, target_dirname)) un_tarball(tar_file) - os.chdir(os.path.join(c.flexpart_root_scripts + os.path.sep + - target_dirname + os.path.sep + - _config.PATH_RELATIVE_FORTRAN_SRC)) + os.chdir(os.path.join(c.flexpart_root_scripts, + target_dirname, + _config.PATH_REL_FORTRAN_SRC)) # Create Fortran executable - CONVERT2 print('Install ' + target_dirname + ' software at ' + @@ -231,12 +232,12 @@ def install_via_gateway(c): make_convert_build('.', c.makefile) os.chdir(ecd) - if os.path.isfile(tar_file): - os.remove(tar_file) +# if os.path.isfile(tar_file): +# os.remove(tar_file) return -def mk_tarball(tarball_path): +def mk_tarball(tarball_path, target): ''' @Description: Creates a tarball with all necessary files which need to be sent to the @@ -251,6 +252,9 @@ def mk_tarball(tarball_path): The complete path to the tar file which will contain all relevant data for flex_extract. + target: string + The queue where the job is submitted to. + @Return: <nothing> ''' @@ -265,25 +269,24 @@ def mk_tarball(tarball_path): os.chdir(ecd) # get lists of the files to be added to the tar file - ECMWF_ENV_FILE = [os.path.join(_config.PATH_RELATIVE_PYTHON + - os.path.sep + _config.FILE_USER_ENVVARS)] - pyfiles = [os.path.relpath(x,ecd) - for x in glob(_config.PATH_LOCAL_PYTHON + - os.path.sep + '*py')] - controlfiles = [os.path.relpath(x,ecd) - for x in glob(_config.PATH_CONTROLFILES + - os.path.sep + 'CONTROL*')] - tempfiles = [os.path.relpath(x,ecd) - for x in glob(_config.PATH_TEMPLATES)] - ffiles = [os.path.relpath(x,ecd) - for x in glob(_config.PATH_FORTRAN_SRC + - os.path.sep + '*.f*')] - hfiles = [os.path.relpath(x,ecd) - for x in glob(_config.PATH_FORTRAN_SRC + - os.path.sep + '*.h')] - makefiles = [os.path.relpath(x,ecd) - for x in glob(_config.PATH_FORTRAN_SRC + - os.path.sep + 'Makefile*')] + if target == 'local': + ECMWF_ENV_FILE = [] + else: + ECMWF_ENV_FILE = [_config.PATH_REL_ECMWF_ENV] + + pyfiles = [os.path.relpath(x, ecd) + for x in UioFiles(_config.PATH_LOCAL_PYTHON, '*py').files] + controlfiles = [os.path.relpath(x, ecd) + for x in UioFiles(_config.PATH_CONTROLFILES, + 'CONTROL*').files] + tempfiles = [os.path.relpath(x, ecd) + for x in UioFiles(_config.PATH_TEMPLATES , '*').files] + ffiles = [os.path.relpath(x, ecd) + for x in UioFiles(_config.PATH_FORTRAN_SRC, '*.f*').files] + hfiles = [os.path.relpath(x, ecd) + for x in UioFiles(_config.PATH_FORTRAN_SRC, '*.h').files] + makefiles = [os.path.relpath(x, ecd) + for x in UioFiles(_config.PATH_FORTRAN_SRC, 'Makefile*').files] # concatenate single lists to one for a better looping filelist = pyfiles + controlfiles + tempfiles + ffiles + hfiles + \ @@ -350,8 +353,7 @@ def mk_env_vars(ecuid, ecgid, gateway, destination): <nothing> ''' - with open(os.path.join(_config.PATH_LOCAL_PYTHON + os.path.sep + - _config.FILE_USER_ENVVARS), 'w') as fo: + with open(_config.PATH_REL_ECMWF_ENV, 'w') as fo: fo.write('ECUID ' + ecuid + '\n') fo.write('ECGID ' + ecgid + '\n') fo.write('GATEWAY ' + gateway + '\n') @@ -388,12 +390,12 @@ def mk_compilejob(makefile, target, ecuid, ecgid, fp_root): <nothing> ''' - template = os.path.join(_config.PATH_TEMPLATES + os.path.sep + + template = os.path.join(_config.PATH_REL_TEMPLATES, _config.TEMPFILE_INSTALL_COMPILEJOB) with open(template) as f: fdata = f.read().split('\n') - compilejob = os.path.join(_config.PATH_JOBSCRIPTS + os.path.sep + + compilejob = os.path.join(_config.PATH_REL_JOBSCRIPTS, _config.FILE_INSTALL_COMPILEJOB) with open(compilejob, 'w') as fo: for data in fdata: @@ -425,7 +427,7 @@ def mk_job_template(ecuid, ecgid, gateway, destination, fp_root): @Description: Modifies the original job template file so that it is specified for the user and the environment were it will be applied. Result - is stored in a new file "job.temp" in the python directory. + is stored in a new file. @Input: ecuid: string @@ -448,26 +450,25 @@ def mk_job_template(ecuid, ecgid, gateway, destination, fp_root): @Return: <nothing> ''' - ec_python_rel_path = _config.FLEXEXTRACT_DIRNAME + '/' + \ - _config.PATH_RELATIVE_PYTHON + fp_root_path_to_python = os.path.join(fp_root, _config.FLEXEXTRACT_DIRNAME, + _config.PATH_REL_PYTHON) - template = os.path.join(_config.PATH_TEMPLATES + os.path.sep + + template = os.path.join(_config.PATH_REL_TEMPLATES, _config.TEMPFILE_INSTALL_JOB) with open(template) as f: fdata = f.read().split('\n') - jobfile_temp = os.path.join(_config.PATH_JOBSCRIPTS + os.path.sep + + jobfile_temp = os.path.join(_config.PATH_REL_TEMPLATES, _config.TEMPFILE_JOB) with open(jobfile_temp, 'w') as fo: for data in fdata: if '--workdir' in data: - data = '#SBATCH --workdir=/scratch/ms/' + ecgid + \ - '/' + ecuid + data = '#SBATCH --workdir=/scratch/ms/' + ecgid + '/' + ecuid elif '##PBS -o' in data: data = '##PBS -o /scratch/ms/' + ecgid + '/' + \ ecuid + 'flex_ecmwf.$Jobname.$Job_ID.out' elif 'export PATH=${PATH}:' in data: - data += fp_root + '/' + ec_python_rel_path + data += fp_root_path_to_python fo.write(data + '\n') return @@ -515,7 +516,7 @@ def make_convert_build(src_path, makefile): try: print('Using makefile: ' + makefile) p = subprocess.Popen(['make', '-f', - os.path.join(src_path + os.path.sep + makefile)], + os.path.join(src_path, makefile)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -536,7 +537,7 @@ def make_convert_build(src_path, makefile): print(e) else: subprocess.check_call(['ls', '-l', - os.path.join(src_path + os.path.sep + + os.path.join(src_path, _config.FORTRAN_EXECUTABLE)]) return diff --git a/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/__init__.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/__init__.py new file mode 100644 index 0000000..4609bf2 --- /dev/null +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/__init__.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +#******************************************************************************* +# @Author: Anne Philipp (University of Vienna) +# +# @Date: September 2018 +# +# @License: +# (C) Copyright 2015-2018. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# +#******************************************************************************* diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/disaggregation.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/disaggregation.py similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/python/disaggregation.py rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/disaggregation.py diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/get_mars_data.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/get_mars_data.py similarity index 92% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/python/get_mars_data.py rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/get_mars_data.py index bf8e02f..1ccdfa9 100755 --- a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/get_mars_data.py +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/get_mars_data.py @@ -56,16 +56,10 @@ except ImportError: ecapi = False # software specific classes and modules from flex_extract +import _config from tools import my_error, normal_exit, get_cmdline_arguments, read_ecenv -from EcFlexpart import EcFlexpart -from UioFiles import UioFiles - -# add path to pythonpath so that python finds its buddies -LOCAL_PYTHON_PATH = os.path.dirname(os.path.abspath( - inspect.getfile(inspect.currentframe()))) -if LOCAL_PYTHON_PATH not in sys.path: - sys.path.append(LOCAL_PYTHON_PATH) - +from classes.EcFlexpart import EcFlexpart +from classes.UioFiles import UioFiles # ------------------------------------------------------------------------------ # FUNCTION # ------------------------------------------------------------------------------ @@ -88,19 +82,16 @@ def main(): try: c = ControlFile(args.controlfile) except IOError: - try: - c = ControlFile(LOCAL_PYTHON_PATH + args.controlfile) - except IOError: - print 'Could not read CONTROL file "' + args.controlfile + '"' - print 'Either it does not exist or its syntax is wrong.' - print 'Try "' + sys.argv[0].split('/')[-1] + \ - ' -h" to print usage information' - sys.exit(1) + print('Could not read CONTROL file "' + args.controlfile + '"') + print('Either it does not exist or its syntax is wrong.') + print('Try "' + sys.argv[0].split('/')[-1] + \ + ' -h" to print usage information') + sys.exit(1) - env_parameter = read_ecenv(c.ecmwfdatadir + 'python/ECMWF_ENV') + env_parameter = read_ecenv(_config.PATH_ECMWF_ENV) c.assign_args_to_control(args, env_parameter) c.assign_envs_to_control(env_parameter) - c.check_conditions() + c.check_conditions(args.queue) get_mars_data(c) normal_exit(c.mailfail, 'Done!') @@ -285,7 +276,6 @@ def do_retrievement(c, server, start, end, delta_t, fluxes=False): dates = day.strftime("%Y%m%d") + "/to/" + \ end.strftime("%Y%m%d") - print("... retrieve " + dates + " in dir " + c.inputdir) try: diff --git a/python/pythontest/TestInstallTar/test_untar/python/plot_retrieved.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/plot_retrieved.py similarity index 98% rename from python/pythontest/TestInstallTar/test_untar/python/plot_retrieved.py rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/plot_retrieved.py index 45e7bb2..21e27e7 100755 --- a/python/pythontest/TestInstallTar/test_untar/python/plot_retrieved.py +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/plot_retrieved.py @@ -52,14 +52,9 @@ from eccodes import codes_grib_new_from_file, codes_get, codes_release, \ import numpy as np # software specific classes and modules from flex_extract -from ControlFile import ControlFile -from UioFiles import UioFiles - -# add path to pythonpath so that python finds its buddies -LOCAL_PYTHON_PATH = os.path.dirname(os.path.abspath( - inspect.getfile(inspect.currentframe()))) -if LOCAL_PYTHON_PATH not in sys.path: - sys.path.append(LOCAL_PYTHON_PATH) +import _config +from classes.ControlFile import ControlFile +from classes.UioFiles import UioFiles font = {'family': 'monospace', 'size': 12} matplotlib.rcParams['xtick.major.pad'] = '20' diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/prepare_flexpart.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/prepare_flexpart.py similarity index 86% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/python/prepare_flexpart.py rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/prepare_flexpart.py index 088c2a0..4ac0af8 100755 --- a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/prepare_flexpart.py +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/prepare_flexpart.py @@ -56,12 +56,12 @@ import os import inspect import sys import socket -import _config # software specific classes and modules from flex_extract -from UioFiles import UioFiles +import _config +from classes.UioFiles import UioFiles from tools import clean_up, get_cmdline_arguments, read_ecenv -from EcFlexpart import EcFlexpart +from classes.EcFlexpart import EcFlexpart ecapi = 'ecmwf' not in socket.gethostname() try: @@ -70,13 +70,6 @@ try: except ImportError: ecapi = False -# add path to pythonpath so that python finds its buddies -LOCAL_PYTHON_PATH = os.path.dirname(os.path.abspath( - inspect.getfile(inspect.currentframe()))) -if LOCAL_PYTHON_PATH not in sys.path: - sys.path.append(LOCAL_PYTHON_PATH) - - # ------------------------------------------------------------------------------ # FUNCTION # ------------------------------------------------------------------------------ @@ -99,19 +92,16 @@ def main(): try: c = ControlFile(args.controlfile) except IOError: - try: - c = ControlFile(LOCAL_PYTHON_PATH + args.controlfile) - except IOError: - print 'Could not read CONTROL file "' + args.controlfile + '"' - print 'Either it does not exist or its syntax is wrong.' - print 'Try "' + sys.argv[0].split('/')[-1] + \ - ' -h" to print usage information' - sys.exit(1) - - env_parameter = read_ecenv(c.ecmwfdatadir + 'python/ECMWF_ENV') + print('Could not read CONTROL file "' + args.controlfile + '"') + print('Either it does not exist or its syntax is wrong.') + print('Try "' + sys.argv[0].split('/')[-1] + \ + ' -h" to print usage information') + sys.exit(1) + + env_parameter = read_ecenv(_config.PATH_ECMWF_ENV) c.assign_args_to_control(args, env_parameter) c.assign_envs_to_control(env_parameter) - c.check_conditions() + c.check_conditions(args.queue) prepare_flexpart(args.ppid, c) return @@ -169,8 +159,8 @@ def prepare_flexpart(ppid, c): if c.basetime == '00': start = start - datetime.timedelta(days=1) - print 'Prepare ' + start.strftime("%Y%m%d") + \ - "/to/" + end.strftime("%Y%m%d") + print('Prepare ' + start.strftime("%Y%m%d") + + "/to/" + end.strftime("%Y%m%d")) # create output dir if necessary if not os.path.exists(c.outputdir): @@ -181,7 +171,7 @@ def prepare_flexpart(ppid, c): # deaccumulate the flux data flexpart = EcFlexpart(c, fluxes=True) - flexpart.write_namelist(c, 'fort.4') + flexpart.write_namelist(c, _config.FILE_NAMELIST) flexpart.deacc_fluxes(inputfiles, c) # get a list of all files from the root inputdir @@ -196,7 +186,7 @@ def prepare_flexpart(ppid, c): # check if in debugging mode, then store all files # otherwise delete temporary files if int(c.debug) != 0: - print '\nTemporary files left intact' + print('\nTemporary files left intact') else: clean_up(c) diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/profiling.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/profiling.py similarity index 96% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/python/profiling.py rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/profiling.py index 4511af2..a20cad6 100644 --- a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/profiling.py +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/profiling.py @@ -65,7 +65,7 @@ def timefn(fn): t1 = time.time() result = fn(*args, **kwargs) t2 = time.time() - print "@timefn:" + fn.func_name + " took " + str(t2 - t1) + " seconds" + print("@timefn:" + fn.func_name + " took " + str(t2 - t1) + " seconds") return result diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/tools.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/tools.py similarity index 95% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/python/tools.py rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/tools.py index 8e1e405..b2cd1dc 100644 --- a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/tools.py +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/mods/tools.py @@ -139,13 +139,15 @@ def read_ecenv(filename): @Input: filename: string - Name of file where the ECMWV environment parameters are stored. + Path to file where the ECMWV environment parameters are stored. @Return: envs: dict + Contains the environment parameter ecuid, ecgid, gateway + and destination for ECMWF server environments. ''' envs= {} - print filename + with open(filename, 'r') as f: for line in f: data = line.strip().split() @@ -177,7 +179,7 @@ def clean_up(c): <nothing> ''' - print "clean_up" + print("clean_up") cleanlist = glob.glob(c.inputdir + "/*") for clist in cleanlist: @@ -186,7 +188,7 @@ def clean_up(c): if c.ecapi is False and (c.ectrans == '1' or c.ecstorage == '1'): silent_remove(clist) - print "Done" + print("Done") return @@ -210,7 +212,7 @@ def my_error(users, message='ERROR'): <nothing> ''' - print message + print(message) # comment if user does not want email notification directly from python for user in users: @@ -226,11 +228,11 @@ def my_error(users, message='ERROR'): trace = '\n'.join(traceback.format_stack()) pout = p.communicate(input=message + '\n\n' + trace)[0] except ValueError as e: - print 'ERROR: ', e + print('ERROR: ', e) sys.exit('Email could not be sent!') else: - print 'Email sent to ' + os.path.expandvars(user) + ' ' + \ - pout.decode() + print('Email sent to ' + os.path.expandvars(user) + ' ' + + pout.decode()) sys.exit(1) @@ -255,7 +257,7 @@ def normal_exit(users, message='Done!'): <nothing> ''' - print message + print(message) # comment if user does not want notification directly from python for user in users: @@ -270,11 +272,11 @@ def normal_exit(users, message='Done!'): bufsize=1) pout = p.communicate(input=message+'\n\n')[0] except ValueError as e: - print 'ERROR: ', e - print 'Email could not be sent!' + print('ERROR: ', e) + print('Email could not be sent!') else: - print 'Email sent to ' + os.path.expandvars(user) + ' ' + \ - pout.decode() + print('Email sent to ' + os.path.expandvars(user) + ' ' + + pout.decode()) return @@ -394,7 +396,7 @@ def to_param_id(pars, table): ipar.append(int(k)) break else: - print 'Warning: par ' + par + ' not found in table 128' + print('Warning: par ' + par + ' not found in table 128') return ipar @@ -440,7 +442,7 @@ def make_dir(directory): # errno.EEXIST = directory already exists raise # re-raise exception if a different error occured else: - print 'WARNING: Directory {0} already exists!'.format(directory) + print('WARNING: Directory {0} already exists!'.format(directory)) return diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/submit.py b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/submit.py similarity index 77% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/python/submit.py rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/submit.py index 967ed94..9819583 100755 --- a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/submit.py +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/source/python/submit.py @@ -15,6 +15,9 @@ # - applied PEP8 style guide # - added documentation # - minor changes in programming style (for consistence) +# - changed path names to variables from config file +# - added option for writing mars requests to extra file +# additionally,as option without submitting the mars jobs # # @License: # (C) Copyright 2014-2018. @@ -47,11 +50,11 @@ import collections # software specific classes and modules from flex_extract import _config -from tools import normal_exit, get_cmdline_arguments, submit_job_to_ecserver, \ - read_ecenv -from get_mars_data import get_mars_data -from prepare_flexpart import prepare_flexpart -from ControlFile import ControlFile +from mods.tools import (normal_exit, get_cmdline_arguments, + submit_job_to_ecserver, read_ecenv) +from mods.get_mars_data import get_mars_data +from mods.prepare_flexpart import prepare_flexpart +from classes.ControlFile import ControlFile # ------------------------------------------------------------------------------ # FUNCTIONS @@ -72,29 +75,25 @@ def main(): <nothing> ''' - called_from_dir = os.getcwd() - args = get_cmdline_arguments() try: c = ControlFile(args.controlfile) except IOError: - try: - c = ControlFile(_config.PATH_LOCAL_PYTHON + args.controlfile) - except IOError: - print 'Could not read CONTROL file "' + args.controlfile + '"' - print 'Either it does not exist or its syntax is wrong.' - print 'Try "' + sys.argv[0].split('/')[-1] + \ - ' -h" to print usage information' - sys.exit(1) - - env_parameter = read_ecenv(c.ecmwfdatadir + 'python/ECMWF_ENV') + print('Could not read CONTROL file "' + args.controlfile + '"') + print('Either it does not exist or its syntax is wrong.') + print('Try "' + sys.argv[0].split('/')[-1] + \ + ' -h" to print usage information') + sys.exit(1) + + env_parameter = read_ecenv(_config.PATH_ECMWF_ENV) c.assign_args_to_control(args) c.assign_envs_to_control(env_parameter) - c.check_conditions() + c.check_conditions(args.queue) # on local side # on ECMWF server this would also be the local side + called_from_dir = os.getcwd() if args.queue is None: if c.inputdir[0] != '/': c.inputdir = os.path.join(called_from_dir, c.inputdir) @@ -106,7 +105,7 @@ def main(): normal_exit(c.mailfail, 'FLEX_EXTRACT IS DONE!') else: normal_exit(c.mailfail, 'PRINTING MARS_REQUESTS DONE!') - # on ECMWF server + # send files to ECMWF server and install there else: submit(args.job_template, c, args.queue) @@ -119,7 +118,8 @@ def submit(jtemplate, c, queue): @Input: jtemplate: string - Job template file for submission to ECMWF. It contains all necessary + Job template file from sub-directory "_templates" for + submission to ECMWF. It contains all necessary module and variable settings for the ECMWF environment as well as the job call and mail report instructions. Default is "job.temp". @@ -145,17 +145,18 @@ def submit(jtemplate, c, queue): ''' # read template file and get index for CONTROL input - with open(jtemplate) as f: + with open(os.path.join(_config.PATH_TEMPLATES, jtemplate)) as f: lftext = f.read().split('\n') insert_point = lftext.index('EOF') if not c.basetime: # --------- create on demand job script ------------------------------------ if c.maxstep > 24: - print '---- Pure forecast mode! ----' + print('---- Pure forecast mode! ----') else: - print '---- On-demand mode! ----' - job_file = jtemplate[:-4] + 'ksh' + print('---- On-demand mode! ----') + job_file = os.path.join(_config.PATH_JOBSCRIPTS, + jtemplate[:-4] + 'ksh') clist = c.to_list() lftextondemand = lftext[:insert_point] + clist + lftext[insert_point:] @@ -163,13 +164,13 @@ def submit(jtemplate, c, queue): with open(job_file, 'w') as f: f.write('\n'.join(lftextondemand)) - result_code = submit_job_to_ecserver(queue, job_file) + submit_job_to_ecserver(queue, job_file) else: # --------- create operational job script ---------------------------------- - print '---- Operational mode! ----' - job_file = jtemplate[:-5] + 'oper.ksh' - #colist = [] + print('---- Operational mode! ----') + job_file = os.path.join(_config.PATH_JOBSCRIPTS, + jtemplate[:-5] + 'oper.ksh') if c.maxstep: mt = int(c.maxstep) @@ -189,10 +190,10 @@ def submit(jtemplate, c, queue): with open(job_file, 'w') as f: f.write('\n'.join(lftextoper)) - result_code = submit_job_to_ecserver(queue, job_file) + submit_job_to_ecserver(queue, job_file) # -------------------------------------------------------------------------- - print 'You should get an email with subject flex.hostname.pid' + print('You should get an email with subject flex.hostname.pid') return diff --git a/_templates/compilejob.temp b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/templates/compilejob.temp similarity index 100% rename from _templates/compilejob.temp rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/templates/compilejob.temp diff --git a/_templates/ecmwf_grib1_table_128 b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/templates/ecmwf_grib1_table_128 similarity index 100% rename from _templates/ecmwf_grib1_table_128 rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/templates/ecmwf_grib1_table_128 diff --git a/_templates/job.temp b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/templates/job.temp similarity index 91% rename from _templates/job.temp rename to source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/templates/job.temp index a420316..43becc4 100644 --- a/_templates/job.temp +++ b/source/pythontest/TestInstallTar/flex_extract_v7.1_ecgate/templates/job.temp @@ -32,7 +32,7 @@ case $HOST in module unload emos module load grib_api/1.14.5 module load emos/437-r64 - export PATH=${PATH}:${HOME}/flex_extract_v7.1/python + export PATH=${PATH}:${HOME}/flex_extract_v7.1/source/python ;; *cca*) module switch PrgEnv-cray PrgEnv-intel @@ -40,7 +40,7 @@ case $HOST in module load emos module load python export SCRATCH=$TMPDIR - export PATH=${PATH}:${HOME}/flex_extract_v7.1/python + export PATH=${PATH}:${HOME}/flex_extract_v7.1/source/python ;; esac @@ -48,7 +48,7 @@ cd $SCRATCH mkdir -p python$$ cd python$$ -export CONTROL=$PWD/CONTROL +export CONTROL=CONTROL cat >$CONTROL<<EOF EOF diff --git a/python/pythontest/TestPathes.py b/source/pythontest/TestPathes.py similarity index 93% rename from python/pythontest/TestPathes.py rename to source/pythontest/TestPathes.py index 542b4ee..6174484 100644 --- a/python/pythontest/TestPathes.py +++ b/source/pythontest/TestPathes.py @@ -5,7 +5,7 @@ import os import sys import pytest -sys.path.append("../") +sys.path.append("../python") import _config def test_path_localpython(): diff --git a/python/pythontest/TestTools.py b/source/pythontest/TestTools.py similarity index 92% rename from python/pythontest/TestTools.py rename to source/pythontest/TestTools.py index f55ebf9..a4f0673 100644 --- a/python/pythontest/TestTools.py +++ b/source/pythontest/TestTools.py @@ -7,21 +7,18 @@ import subprocess import pipes import pytest -sys.path.append('../') +sys.path.append('../python') import _config -from tools import (get_cmdline_arguments, read_ecenv, clean_up, my_error, - normal_exit, product, silent_remove, init128, to_param_id, - get_list_as_string, make_dir, put_file_to_ecserver, - submit_job_to_ecserver) +from mods.tools import (get_cmdline_arguments, read_ecenv, clean_up, my_error, + normal_exit, product, silent_remove, init128, + to_param_id, get_list_as_string, make_dir, + put_file_to_ecserver, submit_job_to_ecserver) class TestTools(): ''' ''' - def setUp(self): - pass - def test_get_cmdline_arguments(self): cmd_dict_control = {'start_date':'20180101', 'end_date':'20180101', @@ -37,7 +34,8 @@ class TestTools(): 'job_template':'job.sh', 'queue':'ecgate', 'controlfile':'CONTROL.WORK', - 'debug':'1'} + 'debug':'1', + 'request':'0'} sys.argv = ['dummy.py', '--start_date=20180101', @@ -54,7 +52,8 @@ class TestTools(): '--job_template=job.sh', '--queue=ecgate', '--controlfile=CONTROL.WORK', - '--debug=1'] + '--debug=1', + '--request=0'] results = get_cmdline_arguments() @@ -171,6 +170,7 @@ class TestTools(): assert result == '' @pytest.mark.msuser_pw + @pytest.mark.skip(reason="easier to ignore for now - implement in final version") def test_fullsuccess_put_file_to_ecserver(self): ecuid=os.environ['ECUID'] ecgid=os.environ['ECGID'] @@ -189,6 +189,3 @@ class TestTools(): result = submit_job_to_ecserver('ecgate', 'TestData/testfile.txt') assert result.strip().isdigit() == True - -if __name__ == "__main__": - unittest.main() diff --git a/source/pythontest/TestUIOFiles.py b/source/pythontest/TestUIOFiles.py new file mode 100644 index 0000000..239d1f6 --- /dev/null +++ b/source/pythontest/TestUIOFiles.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import sys +import pytest + +sys.path.append('../python') +from classes.UioFiles import UioFiles + + +class TestUioFiles(): + ''' + Test class to test the UIOFiles methods. + ''' + + def test_listFiles(self): + ''' + @Description: + Test the listFiles method from class UIOFiles. + + @Input: + self: instance of TestClass + Class to test the UIOFiles methods. + + @Return: + <nothing> + ''' + # set comparison information + self.testpath = os.path.join(os.path.dirname(__file__), 'TestDir') + self.expected = ['FCGG__SL.20160410.40429.16424.grb', + 'FCOG__ML.20160410.40429.16424.grb', + 'FCSH__ML.20160410.40429.16424.grb', + 'OG_OROLSM__SL.20160410.40429.16424.grb', + 'FCOG_acc_SL.20160409.40429.16424.grb', + 'FCOG__SL.20160410.40429.16424.grb', + 'FCSH__SL.20160410.40429.16424.grb'] + + # Initialise and collect filenames + files = UioFiles(self.testpath, '*.grb') + # get the basename to just check for equality of filenames + filelist = [os.path.basename(f) for f in files.files] + # comparison of expected filenames against the collected ones + assert sorted(self.expected) == sorted(filelist) + + return + diff --git a/python/pythontest/__init__.py b/source/pythontest/__init__.py similarity index 100% rename from python/pythontest/__init__.py rename to source/pythontest/__init__.py diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/python/test_suite.py b/source/pythontest/leos_test_suit.py similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/python/test_suite.py rename to source/pythontest/leos_test_suit.py diff --git a/python/testsuite.json b/source/pythontest/leos_testsuite.json similarity index 100% rename from python/testsuite.json rename to source/pythontest/leos_testsuite.json diff --git a/python/pythontest/pytest.ini b/source/pythontest/pytest.ini similarity index 100% rename from python/pythontest/pytest.ini rename to source/pythontest/pytest.ini diff --git a/python/pythontest/TestInstallTar/test_untar/python/testecmwfapi.py b/source/pythontest/testecmwfapi.py similarity index 93% rename from python/pythontest/TestInstallTar/test_untar/python/testecmwfapi.py rename to source/pythontest/testecmwfapi.py index 90e49ee..41cb170 100644 --- a/python/pythontest/TestInstallTar/test_untar/python/testecmwfapi.py +++ b/source/pythontest/testecmwfapi.py @@ -1,4 +1,6 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- + from ecmwfapi import ECMWFDataServer server = ECMWFDataServer() diff --git a/src/Makefile.CRAY b/src/Makefile.CRAY deleted file mode 100644 index 6ed57be..0000000 --- a/src/Makefile.CRAY +++ /dev/null @@ -1,62 +0,0 @@ -############################################################################### -# -# Top level Makefile for ECMWFDATA7.0 software -# -# Last modified: December 1, 2015 -# -############################################################################### - - -.SUFFIXES: .o .c .c~ .f .f~ .F90 .f90 .f90~ .f95 .f95~ .F .F~ .y .y~ .l .l~ \ - .s .s~ .sh .sh~ .h .h~ .C .C~ .a - - -#GRIB_API_INCLUDE_DIR=/usr/local/gcc-4.9.3/grib1.12.3//include -#GRIB_API_LIB=-openmp -L/usr/local/gcc-4.9.3/grib1.12.3/lib -Bstatic -lgrib_api_f77 -lgrib_api_f90 -lgrib_api -Bdynamic -lm -ljasper -#EMOSLIB=-lemosR64 - -OPT = -DEBUG = -g -LIB = $(GRIB_API_LIBS) $(EMOSLIB) - -FC=ftn $(F90FLAGS) -F90C=ftn $(F90FLAGS) - -FFLAGS = $(OPT) -I. -r8 -I$(GRIB_API_INCLUDE_DIR) -F90FLAGS = $(OPT) -I. -r8 -I$(GRIB_API_INCLUDE_DIR) - -LDFLAGS = $(OPT) - -BINDIR = . - -EXE = CONVERT2 - - -.f.o: - $(F90C) -c $(F90FLAGS) $(DEBUG) $*.f -.f90.o: - $(F90C) -c $(F90FLAGS) $(DEBUG) $*.f90 - -all: ${EXE} - -clean: - rm *.o - -phgrreal.o: phgrreal.f - $(F90C) -c -g -O3 phgrreal.f - -grphreal.o: grphreal.f - $(F90C) -c -g -O3 grphreal.f - -ftrafo.o: ftrafo.f - $(F90C) -c -g -O3 ftrafo.f - -$(BINDIR)/CONVERT2: phgrreal.o grphreal.o ftrafo.o rwGRIB2.o posnam.o preconvert.o - $(F90C) $(DEBUG) $(OPT) -o $(BINDIR)/CONVERT2 ftrafo.o phgrreal.o grphreal.o rwGRIB2.o posnam.o preconvert.o ${LIB} - - -############################################################################### -# -# End of the Makefile -# -############################################################################### diff --git a/src/Makefile.gfortran b/src/Makefile.gfortran deleted file mode 100644 index 58923fa..0000000 --- a/src/Makefile.gfortran +++ /dev/null @@ -1,62 +0,0 @@ -############################################################################### -# -# Top level Makefile for ECMWFDATA7.0 software -# -# Last modified: December 1, 2015 -# -############################################################################### - - -.SUFFIXES: .o .c .c~ .f .f~ .F90 .f90 .f90~ .f95 .f95~ .F .F~ .y .y~ .l .l~ \ - .s .s~ .sh .sh~ .h .h~ .C .C~ .a - - -#GRIB_API_INCLUDE_DIR=/usr/local/gcc-4.9.3/grib1.12.3//include -#GRIB_API_LIB=-openmp -L/usr/local/gcc-4.9.3/grib1.12.3/lib -Bstatic -lgrib_api_f77 -lgrib_api_f90 -lgrib_api -Bdynamic -lm -ljasper -#EMOSLIB=-lemosR64 - -OPT = -g -DEBUG = -g -LIB = $(GRIB_API_LIB) $(EMOSLIB) - -FC=gfortran -m64 -fdefault-real-8 -fcray-pointer -fno-second-underscore -ffixed-line-length-132 -fopenmp -fconvert=big-endian -F90C=gfortran -m64 -fdefault-real-8 -fcray-pointer -fno-second-underscore -ffixed-line-length-132 -fopenmp -fconvert=big-endian - -FFLAGS = $(OPT) -I. -I$(GRIB_API_INCLUDE_DIR) -F90FLAGS = $(OPT) -I. -I$(GRIB_API_INCLUDE_DIR) - -LDFLAGS = $(OPT) - -BINDIR = . - -EXE = CONVERT2 - - -.f.o: - $(F90C) -c $(F90FLAGS) $(DEBUG) $*.f -.f90.o: - $(F90C) -c $(F90FLAGS) $(DEBUG) $*.f90 - -all: ${EXE} - -clean: - rm *.o - -phgrreal.o: phgrreal.f - $(F90C) -c -g -O3 -fopenmp phgrreal.f - -grphreal.o: grphreal.f - $(F90C) -c -g -O3 -fopenmp grphreal.f - -ftrafo.o: ftrafo.f - $(F90C) -c -g -O3 -fopenmp ftrafo.f - -$(BINDIR)/CONVERT2: phgrreal.o grphreal.o ftrafo.o rwGRIB2.o posnam.o preconvert.o - $(F90C) $(DEBUG) $(OPT) -o $(BINDIR)/CONVERT2 ftrafo.o phgrreal.o grphreal.o rwGRIB2.o posnam.o preconvert.o ${LIB} - - -############################################################################### -# -# End of the Makefile -# -############################################################################### diff --git a/src/Makefile.ifort b/src/Makefile.ifort deleted file mode 100644 index 038a168..0000000 --- a/src/Makefile.ifort +++ /dev/null @@ -1,61 +0,0 @@ -############################################################################### -# -# Top level Makefile for ECMWFDATA7.0 software -# -# Last modified: December 1, 2015 -# -############################################################################### - - -.SUFFIXES: .o .c .c~ .f .f~ .F90 .f90 .f90~ .f95 .f95~ .F .F~ .y .y~ .l .l~ \ - .s .s~ .sh .sh~ .h .h~ .C .C~ .a - - -#GRIB_API_INCLUDE_DIR=/usr/local/ifort/grib1.12.3//include -#GRIB_API_LIB=-openmp -L/usr/local/ifort/grib1.12.3/lib -Bstatic -lgrib_api_f77 -lgrib_api_f90 -lgrib_api -Bdynamic -lm -ljasper - -OPT = -g -DEBUG = -g -LIB = $(GRIB_API_LIBS) -lemosR64 -lgfortran - -FC=ifort -132 -traceback -r8 -F90C=ifort -132 -traceback -r8 - -FFLAGS = $(OPT) -I. -I$(GRIB_API_INCLUDE_DIR) -F90FLAGS = $(OPT) -I. -I$(GRIB_API_INCLUDE_DIR) - -LDFLAGS = $(OPT) - -BINDIR = . - -EXE = CONVERT2 - - -.f.o: - $(F90C) -c $(F90FLAGS) -132 $(DEBUG) $*.f -.f90.o: - $(F90C) -c $(F90FLAGS) -132 $(DEBUG) $*.f90 - -all: ${EXE} - -clean: - rm *.o - -phgrreal.o: phgrreal.f - $(F90C) -c -g -O3 -fopenmp phgrreal.f - -grphreal.o: grphreal.f - $(F90C) -c -g -O3 -fopenmp grphreal.f - -ftrafo.o: ftrafo.f - $(F90C) -c -g -O3 -fopenmp ftrafo.f - -$(BINDIR)/CONVERT2: phgrreal.o grphreal.o ftrafo.o rwGRIB2.o posnam.o preconvert.o - $(F90C) $(DEBUG) $(OPT) -o $(BINDIR)/CONVERT2 ftrafo.o phgrreal.o grphreal.o rwGRIB2.o posnam.o preconvert.o ${LIB} - - -############################################################################### -# -# End of the Makefile -# -############################################################################### diff --git a/src/Makefile.local.gfortran b/src/Makefile.local.gfortran deleted file mode 100644 index 3847d57..0000000 --- a/src/Makefile.local.gfortran +++ /dev/null @@ -1,62 +0,0 @@ -############################################################################### -# -# Top level Makefile for ECMWFDATA7.0 software -# -# Last modified: December 1, 2015 -# -############################################################################### - - -.SUFFIXES: .o .c .c~ .f .f~ .F90 .f90 .f90~ .f95 .f95~ .F .F~ .y .y~ .l .l~ \ - .s .s~ .sh .sh~ .h .h~ .C .C~ .a - - -GRIB_API_INCLUDE_DIR=/usr/local/gcc-4.9.3/grib_api-1.14.3//include -GRIB_API_LIB= -L/usr/local/gcc-4.9.3/grib_api-1.14.3/lib -Bstatic -lgrib_api_f77 -lgrib_api_f90 -lgrib_api -Bdynamic -lm -ljasper -EMOSLIB=-lemosR64 - -OPT = -g -O3 -fopenmp -DEBUG = -g -LIB = $(GRIB_API_LIB) $(EMOSLIB) - -FC=gfortran -m64 -fdefault-real-8 -fcray-pointer -fno-second-underscore -ffixed-line-length-132 -fopenmp -fconvert=big-endian -F90C=gfortran -m64 -fdefault-real-8 -fcray-pointer -fno-second-underscore -ffixed-line-length-132 -fopenmp -fconvert=big-endian - -FFLAGS = $(OPT) -I. -I$(GRIB_API_INCLUDE_DIR) -F90FLAGS = $(OPT) -I. -I$(GRIB_API_INCLUDE_DIR) - -LDFLAGS = $(OPT) - -BINDIR = . - -EXE = CONVERT2 - - -.f.o: - $(F90C) -c $(F90FLAGS) $(DEBUG) $*.f -.f90.o: - $(F90C) -c $(F90FLAGS) $(DEBUG) $*.f90 - -all: ${EXE} - -clean: - rm *.o - -phgrreal.o: phgrreal.f - $(F90C) -c -g -O3 -fopenmp phgrreal.f - -grphreal.o: grphreal.f - $(F90C) -c -g -O3 -fopenmp grphreal.f - -ftrafo.o: ftrafo.f - $(F90C) -c -g -O3 -fopenmp ftrafo.f - -$(BINDIR)/CONVERT2: phgrreal.o grphreal.o ftrafo.o rwGRIB2.o posnam.o preconvert.o - $(F90C) $(DEBUG) $(OPT) -o $(BINDIR)/CONVERT2 ftrafo.o phgrreal.o grphreal.o rwGRIB2.o posnam.o preconvert.o ${LIB} - - -############################################################################### -# -# End of the Makefile -# -############################################################################### diff --git a/src/Makefile.local.ifort b/src/Makefile.local.ifort deleted file mode 100644 index 6f58a35..0000000 --- a/src/Makefile.local.ifort +++ /dev/null @@ -1,61 +0,0 @@ -############################################################################### -# -# Top level Makefile for ECMWFDATA7.0 software -# -# Last modified: December 1, 2015 -# -############################################################################### - - -.SUFFIXES: .o .c .c~ .f .f~ .F90 .f90 .f90~ .f95 .f95~ .F .F~ .y .y~ .l .l~ \ - .s .s~ .sh .sh~ .h .h~ .C .C~ .a - - -GRIB_API_INCLUDE_DIR=/home/srvx1/tmc/TestEnv/Libraries/eccodes-2.6.0_ifort/include -GRIB_API_LIB= -L/home/srvx1/tmc/TestEnv/Libraries/eccodes-2.6.0_ifort/lib -Bstatic -leccodes_f90 -leccodes -Bdynamic -lm -ljasper - -OPT = -g -O3 -mcmodel=medium -unroll -inline -heap-arrays 32 -DEBUG = -g -LIB = $(GRIB_API_LIB) -lemosR64 -lgfortran - -FC=/opt/intel/bin/ifort -132 -traceback -r8 -F90C=/opt/intel/bin/ifort -132 -traceback -r8 - -FFLAGS = $(OPT) -I. -I$(GRIB_API_INCLUDE_DIR) -F90FLAGS = $(OPT) -I. -I$(GRIB_API_INCLUDE_DIR) - -LDFLAGS = $(OPT) - -BINDIR = . - -EXE = CONVERT2 - - -.f.o: - $(F90C) -c $(F90FLAGS) -132 $(DEBUG) $*.f -.f90.o: - $(F90C) -c $(F90FLAGS) -132 $(DEBUG) $*.f90 - -all: ${EXE} - -clean: - rm *.o - -phgrreal.o: phgrreal.f - $(F90C) -c -g -O3 phgrreal.f - -grphreal.o: grphreal.f - $(F90C) -c -g -O3 grphreal.f - -ftrafo.o: ftrafo.f - $(F90C) -c -g -O3 ftrafo.f - -$(BINDIR)/CONVERT2: phgrreal.o grphreal.o ftrafo.o rwGRIB2.o posnam.o preconvert.o - $(F90C) $(DEBUG) $(OPT) -o $(BINDIR)/CONVERT2 ftrafo.o phgrreal.o grphreal.o rwGRIB2.o posnam.o preconvert.o ${LIB} - - -############################################################################### -# -# End of the Makefile -# -############################################################################### diff --git a/src/Makefile.new b/src/Makefile.new deleted file mode 100644 index 9953d13..0000000 --- a/src/Makefile.new +++ /dev/null @@ -1,61 +0,0 @@ -############################################################################### -# -# Top level Makefile for ECMWFDATA7.0 software -# -# Last modified: December 1, 2015 -# -############################################################################### - - -.SUFFIXES: .o .c .c~ .f .f~ .F90 .f90 .f90~ .f95 .f95~ .F .F~ .y .y~ .l .l~ \ - .s .s~ .sh .sh~ .h .h~ .C .C~ .a - - -GRIB_API_INCLUDE_DIR=/usr/local/ifort/grib1.12.3//include -GRIB_API_LIBS=-openmp -L/usr/local/ifort/grib1.12.3/lib -Bstatic -lgrib_api_f77 -lgrib_api_f90 -lgrib_api -Bdynamic -lm -ljasper - -OPT = -g -DEBUG = -g -LIB = $(GRIB_API_LIBS) -lemosR64 - -FC=ifort -132 -traceback -r8 -F90C=ifort -132 -traceback -r8 - -FFLAGS = $(OPT) -I. -I$(GRIB_API_INCLUDE_DIR) -F90FLAGS = $(OPT) -I. -I$(GRIB_API_INCLUDE_DIR) - -LDFLAGS = $(OPT) - -BINDIR = . - -EXE = CONVERT2 - - -.f.o: - $(F90C) -c $(F90FLAGS) -132 $(DEBUG) $*.f -.f90.o: - $(F90C) -c $(F90FLAGS) -132 $(DEBUG) $*.f90 - -all: ${EXE} - -clean: - rm *.o - -phgrreal.o: phgrreal.f - $(F90C) -c -g -O3 -fopenmp phgrreal.f - -grphreal.o: grphreal.f - $(F90C) -c -g -O3 -fopenmp grphreal.f - -ftrafo.o: ftrafo.f - $(F90C) -c -g -O3 -fopenmp ftrafo.f - -$(BINDIR)/CONVERT2: phgrreal.o grphreal.o ftrafo.o rwGRIB2.o posnam.o preconvert.o - $(F90C) $(DEBUG) $(OPT) -o $(BINDIR)/CONVERT2 ftrafo.o phgrreal.o grphreal.o rwGRIB2.o posnam.o preconvert.o ${LIB} - - -############################################################################### -# -# End of the Makefile -# -############################################################################### diff --git a/src/ftrafo.f b/src/ftrafo.f deleted file mode 100644 index affdccd..0000000 --- a/src/ftrafo.f +++ /dev/null @@ -1,504 +0,0 @@ - MODULE FTRAFO - - CONTAINS - - - -C -C Implementierung der spektralen Transformationsmethode unter Verwendung -C des reduzierten Gauss'schen Gitters -C -C Berechnung der scale winds aus Vorticity und Divergenz -C uebergibt man in XMN die Divergenz, so wird der divergente Anteil des -C Windes (XPHI=Ud,XPHI=Vd) zurueckgegeben, uebergibt man die Vorticity, so -C erhaelt man den rotationellen Wind (XLAM=Vrot,XPHI=-Urot). -C Summiert man beide, erhaelt man den gesamten Scale wind -C GWSAVE ist ein Hilfsfeld fuer die FFT -C P enthaelt die assoziierten Legendrepolynome, H deren Ableitung -C MLAT enthaelt die Anzahl der Gitterpunkte pro Breitenkreis -C MNAUF gibt die spektrale Aufloesung an, -C NI = Anzahl der Gauss'schen Gitterpunkte pro Flaeche -C NJ = Anzahl der Gauss'schen Breiten, -C NK = Anzahl der Niveaus - - SUBROUTINE VDTOUV(XMN,XLAM,XPHI,GWSAVE,IFAX,P,MLAT,MNAUF,NI,NJ,NK) - - - USE PHTOGR - - IMPLICIT NONE - INTEGER J,N,NI,NJ,NK,MNAUF,GGIND(NJ/2) - INTEGER MLAT(NJ),IFAX(10,NJ) - REAL XMN(0:(MNAUF+1)*(MNAUF+2)-1,NK) - REAL P(0:(MNAUF+3)*(MNAUF+4)/2,NJ/2) - REAL H(0:(MNAUF+2)*(MNAUF+3)/2) - REAL XLAM(NI,NK),XPHI(NI,NK) - REAL GWSAVE(8*NJ+15,NJ/2) - REAL SCR,SCI,ACR,ACI,MUSCR,MUSCI,MUACR,MUACI - REAL RT,IT - - GGIND(1)=0 - DO 4 J = 2,NJ/2 - GGIND(J)=GGIND(J-1)+MLAT(J-1) -4 CONTINUE -!$OMP PARALLEL DO SCHEDULE(DYNAMIC) - DO 5 J = 1,NJ/2 - CALL VDUVSUB(J,XMN,XLAM,XPHI,GWSAVE,IFAX,P,GGIND(J), - *MLAT,MNAUF,NI,NJ,NK) - 5 CONTINUE -!$OMP END PARALLEL DO - RETURN - END SUBROUTINE VDTOUV - - SUBROUTINE VDUVSUB(J,XMN,XLAM,XPHI,GWSAVE,IFAX,P, - *GGIND,MLAT,MNAUF,NI,NJ,NK) - - USE PHTOGR - - IMPLICIT NONE - INTEGER J,K,M,N,NI,NJ,NK,MNAUF,GGIND,LL,LLP,LLH,LLS,LLPS,LLHS - INTEGER MLAT(NJ),IFAX(10,NJ) - REAL UFOUC(0:MAXAUF),MUFOUC(0:MAXAUF) - REAL VFOUC(0:MAXAUF),MVFOUC(0:MAXAUF) - REAL XMN(0:(MNAUF+1)*(MNAUF+2)-1,NK) - REAL P(0:(MNAUF+3)*(MNAUF+4)/2,NJ/2) - REAL H(0:(MNAUF+2)*(MNAUF+3)/2) - REAL XLAM(NI,NK),XPHI(NI,NK) - REAL GWSAVE(8*NJ+15,NJ/2) - REAL ERAD,SCR,SCI,ACR,ACI,MUSCR,MUSCI,MUACR,MUACI - REAL FAC(0:MNAUF),RT,IT - - - ERAD = 6367470.D0 - - FAC(0)=0.D0 - DO 12 N=1,MNAUF - FAC(N)=-ERAD/DBLE(N)/DBLE(N+1) -12 CONTINUE - - CALL DPLGND(MNAUF,P(0,J),H) - DO 3 K = 1,NK - LL=0 - LLP=0 - LLH=0 - DO 2 M = 0,MNAUF - SCR=0.D0 - SCI=0.D0 - ACR=0.D0 - ACI=0.D0 - MUSCR=0.D0 - MUSCI=0.D0 - MUACR=0.D0 - MUACI=0.D0 - LLS=LL - LLPS=LLP - LLHS=LLH - IF(2*M+1.LT.MLAT(J)) THEN - DO 1 N = M,MNAUF,2 - RT=XMN(2*LL,K)*FAC(N) - IT=XMN(2*LL+1,K)*FAC(N) - SCR =SCR+ RT*P(LLP,J) - SCI =SCI+ IT*P(LLP,J) - MUACR =MUACR+ RT*H(LLH) - MUACI =MUACI+ IT*H(LLH) - LL=LL+2 - LLP=LLP+2 - LLH=LLH+2 - 1 CONTINUE - LL=LLS+1 - LLP=LLPS+1 - LLH=LLHS+1 - DO 11 N = M+1,MNAUF,2 - RT=XMN(2*LL,K)*FAC(N) - IT=XMN(2*LL+1,K)*FAC(N) - ACR =ACR+ RT*P(LLP,J) - ACI =ACI+ IT*P(LLP,J) - MUSCR =MUSCR+ RT*H(LLH) - MUSCI =MUSCI+ IT*H(LLH) - LL=LL+2 - LLP=LLP+2 - LLH=LLH+2 - 11 CONTINUE - ENDIF - LL=LLS+(MNAUF-M+1) - LLP=LLPS+(MNAUF-M+3) - LLH=LLHS+(MNAUF-M+2) - - UFOUC(2*M)=-M*(SCI-ACI) - UFOUC(2*M+1)=M*(SCR-ACR) - VFOUC(2*M)=-M*(SCI+ACI) - VFOUC(2*M+1)=M*(SCR+ACR) - - MUFOUC(2*M)=-(MUSCR-MUACR) - MUFOUC(2*M+1)=-(MUSCI-MUACI) - MVFOUC(2*M)=-(MUSCR+MUACR) - MVFOUC(2*M+1)=-(MUSCI+MUACI) - 2 CONTINUE - - CALL RFOURTR(VFOUC, - *GWSAVE(:,J),IFAX(:,J),MNAUF,MLAT(J),1) - XLAM(GGIND+1:GGIND+MLAT(J),K)=VFOUC(0:MLAT(J)-1) - CALL RFOURTR(UFOUC, - *GWSAVE(:,J),IFAX(:,J),MNAUF,MLAT(J),1) - XLAM(NI-GGIND-MLAT(J)+1:NI-GGIND,K)=UFOUC(0:MLAT(J)-1) - - CALL RFOURTR(MVFOUC, - *GWSAVE(:,J),IFAX(:,J),MNAUF,MLAT(J),1) - XPHI(GGIND+1:GGIND+MLAT(J),K)=MVFOUC(0:MLAT(J)-1) - CALL RFOURTR(MUFOUC, - *GWSAVE(:,J),IFAX(:,J),MNAUF,MLAT(J),1) - XPHI(NI-GGIND-MLAT(J)+1:NI-GGIND,K)=MUFOUC(0:MLAT(J)-1) - -3 CONTINUE - - RETURN - END SUBROUTINE VDUVSUB - -C Berechnung des Gradienten eines Skalars aus dem Feld des -C Skalars XMN im Phasenraum. Zurueckgegeben werden die Felder der -C Komponenten des horizontalen Gradienten XLAM,XPHI auf dem Gauss'schen Gitter. -C GWSAVE ist ein Hilfsfeld fuer die FFT -C P enthaelt die assoziierten Legendrepolynome, H deren Ableitung -C MLAT enthaelt die Anzahl der Gitterpunkte pro Breitenkreis -C MNAUF gibt die spektrale Aufloesung an, -C NI = Anzahl der Gauss'schen Gitterpunkte, -C NJ = Anzahl der Gauss'schen Breiten, -C NK = Anzahl der Niveaus - - SUBROUTINE PHGRAD(XMN,XLAM,XPHI,GWSAVE,IFAX,P,H,MLAT, - *MNAUF,NI,NJ,NK) - - USE PHTOGR - IMPLICIT NONE - INTEGER J,K,M,N,NI,NJ,NK,MNAUF,GGIND,LL,LLP,LLH,LLS,LLPS,LLHS - INTEGER MLAT(NJ),IFAX(10,NJ) - REAL UFOUC(0:MAXAUF),MUFOUC(0:MAXAUF) - REAL VFOUC(0:MAXAUF),MVFOUC(0:MAXAUF) - REAL XMN(0:(MNAUF+1)*(MNAUF+2)-1,NK) - REAL P(0:(MNAUF+3)*(MNAUF+4)/2,NJ/2) - REAL H(0:(MNAUF+2)*(MNAUF+3)/2) - REAL XLAM(NI,NK),XPHI(NI,NK) - REAL GWSAVE(8*NJ+15,NJ/2) - REAL ERAD - REAL SCR,SCI,ACR,ACI,MUSCR,MUSCI,MUACR,MUACI,RT,IT - - ERAD = 6367470.0 - - GGIND=0 - DO 4 J = 1,NJ/2 - CALL DPLGND(MNAUF,P(0,J),H) - DO 3 K = 1,NK - LL=0 - LLP=0 - LLH=0 - DO 2 M = 0,MNAUF - SCR=0.D0 - SCI=0.D0 - ACR=0.D0 - ACI=0.D0 - MUSCR=0.D0 - MUSCI=0.D0 - MUACR=0.D0 - MUACI=0.D0 - LLS=LL - LLPS=LLP - LLHS=LLH - IF(2*M+1.LT.MLAT(J)) THEN - DO 1 N = M,MNAUF,2 - RT=XMN(2*LL,K) - IT=XMN(2*LL+1,K) - SCR =SCR+ RT*P(LLP,J) - SCI =SCI+ IT*P(LLP,J) - MUACR =MUACR+RT*H(LLH) - MUACI =MUACI+ IT*H(LLH) - LL=LL+2 - LLP=LLP+2 - LLH=LLH+2 - 1 CONTINUE - LL=LLS+1 - LLP=LLPS+1 - LLH=LLHS+1 - DO 11 N = M+1,MNAUF,2 - RT=XMN(2*LL,K) - IT=XMN(2*LL+1,K) - ACR =ACR+ RT*P(LLP,J) - ACI =ACI+ IT*P(LLP,J) - MUSCR =MUSCR+ RT*H(LLH) - MUSCI =MUSCI+ IT*H(LLH) - LL=LL+2 - LLP=LLP+2 - LLH=LLH+2 - 11 CONTINUE - ENDIF - LL=LLS+(MNAUF-M+1) - LLP=LLPS+(MNAUF-M+3) - LLH=LLHS+(MNAUF-M+2) - - UFOUC(2*M)=-M*(SCI-ACI)/ERAD - UFOUC(2*M+1)=M*(SCR-ACR)/ERAD - VFOUC(2*M)=-M*(SCI+ACI)/ERAD - VFOUC(2*M+1)=M*(SCR+ACR)/ERAD - - MUFOUC(2*M)=-(MUSCR-MUACR)/ERAD - MUFOUC(2*M+1)=-(MUSCI-MUACI)/ERAD - MVFOUC(2*M)=-(MUSCR+MUACR)/ERAD - MVFOUC(2*M+1)=-(MUSCI+MUACI)/ERAD -2 CONTINUE - - CALL RFOURTR(VFOUC, - *GWSAVE(:,J),IFAX(:,J),MNAUF,MLAT(J),1) - XLAM(GGIND+1:GGIND+MLAT(J),K)=VFOUC(0:MLAT(J)-1) - CALL RFOURTR(UFOUC, - *GWSAVE(:,J),IFAX(:,J),MNAUF,MLAT(J),1) - XLAM(NI-GGIND-MLAT(J)+1:NI-GGIND,K)=UFOUC(0:MLAT(J)-1) - - CALL RFOURTR(MVFOUC, - *GWSAVE(:,J),IFAX(:,J),MNAUF,MLAT(J),1) - XPHI(GGIND+1:GGIND+MLAT(J),K)=MVFOUC(0:MLAT(J)-1) - CALL RFOURTR(MUFOUC, - *GWSAVE(:,J),IFAX(:,J),MNAUF,MLAT(J),1) - XPHI(NI-GGIND-MLAT(J)+1:NI-GGIND,K)=MUFOUC(0:MLAT(J)-1) - -3 CONTINUE - GGIND=GGIND+MLAT(J) -4 CONTINUE - - - RETURN - END SUBROUTINE PHGRAD - -C Berechnung des Gradienten eines Skalars aus dem Feld des -C Skalars XMN im Phasenraum. Zurueckgegeben werden die Felder der -C Komponenten des horizontalen Gradienten XLAM,XPHI auf dem Gauss'schen Gitter. -C GWSAVE ist ein Hilfsfeld fuer die FFT -C P enthaelt die assoziierten Legendrepolynome, H deren Ableitung -C MLAT enthaelt die Anzahl der Gitterpunkte pro Breitenkreis -C MNAUF gibt die spektrale Aufloesung an, -C NI = Anzahl der Gauss'schen Gitterpunkte, -C NJ = Anzahl der Gauss'schen Breiten, -C NK = Anzahl der Niveaus - - SUBROUTINE PHGRACUT(XMN,XLAM,XPHI,GWSAVE,IFAX,P,H,MAUF, - *MNAUF,NI,NJ,MANF,NK) - - USE PHTOGR - IMPLICIT NONE - INTEGER J,K,M,N,NI,NJ,NK,MNAUF,GGIND,LL,LLP,LLH,LLS,LLPS,LLHS - INTEGER MAUF,MANF,I,IFAX(10) - REAL UFOUC(0:MAXAUF),MUFOUC(0:MAXAUF) - REAL VFOUC(0:MAXAUF),MVFOUC(0:MAXAUF) - REAL XMN(0:(MNAUF+1)*(MNAUF+2)-1,NK) - REAL P(0:(MNAUF+3)*(MNAUF+4)/2,NJ) - REAL H(0:(MNAUF+2)*(MNAUF+3)/2) - REAL XLAM(NI,NJ,NK),XPHI(NI,NJ,NK) - REAL HLAM(MAXAUF,2),HPHI(MAXAUF,2) - REAL GWSAVE(4*MAUF+15) - REAL ERAD - REAL SCR,SCI,ACR,ACI,MUSCR,MUSCI,MUACR,MUACI,RT,IT - - ERAD = 6367470.0 - - GGIND=0 - DO 4 J = 1,NJ - CALL DPLGND(MNAUF,P(0,J),H) - DO 3 K = 1,NK - LL=0 - LLP=0 - LLH=0 - DO 2 M = 0,MNAUF - SCR=0.D0 - SCI=0.D0 - ACR=0.D0 - ACI=0.D0 - MUSCR=0.D0 - MUSCI=0.D0 - MUACR=0.D0 - MUACI=0.D0 - LLS=LL - LLPS=LLP - LLHS=LLH - IF(2*M+1.LT.MAUF) THEN - DO 1 N = M,MNAUF,2 - RT=XMN(2*LL,K) - IT=XMN(2*LL+1,K) - SCR =SCR+ RT*P(LLP,J) - SCI =SCI+ IT*P(LLP,J) - MUACR =MUACR+RT*H(LLH) - MUACI =MUACI+ IT*H(LLH) - LL=LL+2 - LLP=LLP+2 - LLH=LLH+2 - 1 CONTINUE - LL=LLS+1 - LLP=LLPS+1 - LLH=LLHS+1 - DO 11 N = M+1,MNAUF,2 - RT=XMN(2*LL,K) - IT=XMN(2*LL+1,K) - ACR =ACR+ RT*P(LLP,J) - ACI =ACI+ IT*P(LLP,J) - MUSCR =MUSCR+ RT*H(LLH) - MUSCI =MUSCI+ IT*H(LLH) - LL=LL+2 - LLP=LLP+2 - LLH=LLH+2 - 11 CONTINUE - ENDIF - LL=LLS+(MNAUF-M+1) - LLP=LLPS+(MNAUF-M+3) - LLH=LLHS+(MNAUF-M+2) - - UFOUC(2*M)=-M*(SCI-ACI)/ERAD - UFOUC(2*M+1)=M*(SCR-ACR)/ERAD - VFOUC(2*M)=-M*(SCI+ACI)/ERAD - VFOUC(2*M+1)=M*(SCR+ACR)/ERAD - - MUFOUC(2*M)=-(MUSCR-MUACR)/ERAD - MUFOUC(2*M+1)=-(MUSCI-MUACI)/ERAD - MVFOUC(2*M)=-(MUSCR+MUACR)/ERAD - MVFOUC(2*M+1)=-(MUSCI+MUACI)/ERAD -2 CONTINUE - - CALL RFOURTR(VFOUC, - *GWSAVE,IFAX,MNAUF,MAUF,1) - - CALL RFOURTR(MVFOUC, - *GWSAVE,IFAX,MNAUF,MAUF,1) - - DO 6 I=0,NI-1 - IF(MANF+I.LE. MAUF) THEN - XLAM(I+1,J,K)=VFOUC(MANF+I-1) - XPHI(I+1,J,K)=MVFOUC(MANF+I-1) - ELSE - XLAM(I+1,J,K)=VFOUC(MANF-MAUF+I-1) - XPHI(I+1,J,K)=MVFOUC(MANF-MAUF+I-1) - ENDIF - 6 CONTINUE -3 CONTINUE - GGIND=GGIND+MAUF -4 CONTINUE - - RETURN - END SUBROUTINE PHGRACUT - -C Berechnung der Divergenz aus dem Windfeld (U,V) -C im Phasenraum. Zurueckgegeben werden die Felder der -C Komponenten des horizontalen Gradienten XLAM,XPHI auf dem Gauss'schen Gitter. -C GWSAVE ist ein Hilfsfeld fuer die FFT -C P enthaelt die assoziierten Legendrepolynome, H deren Ableitung -C MLAT enthaelt die Anzahl der Gitterpunkte pro Breitenkreis -C MNAUF gibt die spektrale Aufloesung an, -C NI = Anzahl der Gauss'schen Gitterpunkte, -C NJ = Anzahl der Gauss'schen Breiten, -C NK = Anzahl der Niveaus -C Beachte, dass das Windfeld eine um 1 erhoehte Aufloesung in mu-Richtung hat. - - SUBROUTINE CONTGL(PS,DPSDL,DPSDM,DIV,U,V,BREITE,ETA, - *MLAT,A,B,NI,NJ,NK) - - IMPLICIT NONE - - INTEGER NI,NJ,NK,I,J,K,MLAT(NJ),L - - REAL A(NK+1),B(NK+1) - REAL PS(NI),DPSDL(NI),DPSDM(NI) - REAL DIV(NI,NK),U(NI,NK),V(NI,NK),ETA(NI,NK) - REAL BREITE(NJ) - - REAL DIVT1,DIVT2,POB,PUN,DPSDT,COSB - - L=0 - DO 4 J=1,NJ - COSB=(1.0-BREITE(J)*BREITE(J)) - DO 3 I=1,MLAT(J) - L=L+1 - DIVT1=0.0 - DIVT2=0.0 - DO 1 K=1,NK - POB=A(K)+B(K)*PS(L) - PUN=A(K+1)+B(K+1)*PS(L) - - DIVT1=DIVT1+DIV(L,K)*(PUN-POB) - if(cosb .gt. 0.) then - DIVT2=DIVT2+(B(K+1)-B(K))*PS(L)* - *(U(L,K)*DPSDL(L)+V(L,K)*DPSDM(L))/COSB - endif - - ETA(L,K)=-DIVT1-DIVT2 -1 CONTINUE - - DPSDT=(-DIVT1-DIVT2)/PS(L) - - DO 2 K=1,NK - ETA(L,K)=ETA(L,K)-DPSDT*B(K+1)*PS(L) -2 CONTINUE - PS(L)=DPSDT*PS(L) -3 CONTINUE -4 CONTINUE - RETURN - END SUBROUTINE CONTGL - -C OMEGA berechnet omega im Hybridkoordinatensystem -C PS ist der Bodendruck, -C DPSDL,DPSDM sind die Komponenten des Gradienten des Logarithmus des -C Bodendrucks -C DIV,U,V sind die horizontale Divergenz und das horizontale Windfeld -C BREITE ist das Feld der Gauss'schen Breiten -C E ist omega, - - SUBROUTINE OMEGA(PS,DPSDL,DPSDM,DIV,U,V,BREITE,E,MLAT,A,B,NGI - * ,NGJ,MKK) - - IMPLICIT NONE - - INTEGER I,J,K,L,NGI,NGJ,MKK,MLAT(NGJ) - - REAL PS(NGI),DPSDL(NGI),DPSDM(NGI),A(MKK+1),B(MKK+1) - REAL DIV(NGI,MKK),U(NGI,MKK),V(NGI,MKK),E(NGI,MKK) - REAL BREITE(NGJ) - - REAL DIVT1,DIVT2,POB,PUN,DP,X,Y,COSB - REAL DIVT3(MKK+2) - - L=0 - DO 4 J=1,NGJ - COSB=(1.0-BREITE(J)*BREITE(J)) - DO 3 I=1,MLAT(J) - L=L+1 - DIVT1=0.0 - DIVT2=0.0 - DIVT3(1)=0.0 - DO 1 K=1,MKK - POB=A(K)+B(K)*PS(L) - PUN=A(K+1)+B(K+1)*PS(L) - DP=PUN-POB - - Y=PS(L)*(U(L,K)*DPSDL(L)+V(L,K)*DPSDM(L))/COSB - IF(K.LT.3) THEN - X=0.0 - ELSE - X=(B(K+1)-B(K))*Y - ENDIF - - DIVT1=DIVT1+DIV(L,K)*DP - DIVT2=DIVT2+X - - DIVT3(K+1)=-DIVT1-DIVT2 - - IF(K.GT.1) THEN - E(L,K) = 0.5*(POB+PUN)/DP*Y* - *((B(K+1)-B(K))+(A(K+1)*B(K)-A(K)*B(K+1))/ - *DP*LOG(PUN/POB)) - ELSE - E(L,K) = 0.0 - ENDIF - - E(L,K) = E(L,K)+0.5*(DIVT3(K)+DIVT3(K+1)) - -1 CONTINUE -3 CONTINUE -4 CONTINUE - RETURN - END SUBROUTINE OMEGA - - END MODULE FTRAFO diff --git a/src/grphreal.f b/src/grphreal.f deleted file mode 100644 index dae342b..0000000 --- a/src/grphreal.f +++ /dev/null @@ -1,188 +0,0 @@ - MODULE GRTOPH - - USE PHTOGR - - CONTAINS -C - SUBROUTINE GRPH213(CXMN,FELD,WSAVE,IFAX,Z,W,MLAT, - *MNAUF,MAXL,MAXB,MLEVEL) - -C DIE ROUTINE F]HRT EINE TRANSFORMATION EINER -C FELDVARIABLEN VOM PHASENRAUM IN DEN PHYSIKALISCHEN -C RAUM AUF KUGELKOORDINATEN DURCH -C -C CXMN = SPEKTRALKOEFFIZIENTEN IN DER REIHENFOLGE -C CX00,CX01,CX11,CX02,....CXMNAUFMNAUF -C CXM = FOURIERKOEFFIZIENTEN - nur ein Hilfsfeld -C FELD = FELD DER METEOROLOGISCHEN VARIABLEN -C WSAVE = Working Array fuer Fouriertransformation -C Z = LEGENDREFUNKTIONSWERTE -C -C MNAUF ANZAHL DER FOURIERKOEFFIZIENTEN -C MAXL ANZAHL DER FUER DAS GITTER BENUTZTEN LAENGEN -C MAXB ANZAHL DER FUER DAS GITTER BENOETIGTEN BREITEN -C MLEVEL ANZAHL DER LEVELS, DIE TRANSFORMIERT WERDEN -C - IMPLICIT REAL (A-H,O-Z) - - -C Anzahl der Gitterpunkte pro Breitenkreis des reduzierten -C Gauss'schen Gitters - INTEGER MLAT(MAXB),ISIZE,IFAX(10,MAXB) - -C FELD DER LEGENDREPOLYNOME FUER EINE BREITE - REAL*8 Z(MAXB/2,0:((MNAUF+3)*(MNAUF+4))/2) - -C LOGICAL*1 USED(((216*217)/2+1)*160) - - DIMENSION CXMN(0:(MNAUF+1)*(MNAUF+2)-1,MLEVEL) - REAL FELD(MAXL,MLEVEL) - DIMENSION WSAVE(8*MAXB+15,MAXB/2) - REAL*8 W(MAXB) - DIMENSION IND(MAXB) - - - IND(1)=0 - DO 6 J=2,MAXB/2 - IND(j)=IND(J-1)+MLAT(J-1) - 6 CONTINUE -!$OMP PARALLEL DO SCHEDULE(DYNAMIC) - DO 16 L=1,MLEVEL - CALL GRPHSUB(L,IND,CXMN,FELD,WSAVE,IFAX,Z,W,MLAT, - *MNAUF,MAXL,MAXB,MLEVEL) -16 CONTINUE -!$omp end parallel do - - - RETURN - END SUBROUTINE GRPH213 -C - SUBROUTINE GRPHSUB(L,IND,CXMN,FELD,WSAVE,IFAX,Z,W,MLAT, - *MNAUF,MAXL,MAXB,MLEVEL) - -C DIE ROUTINE F]HRT EINE TRANSFORMATION EINER -C FELDVARIABLEN VOM PHASENRAUM IN DEN PHYSIKALISCHEN -C RAUM AUF KUGELKOORDINATEN DURCH -C -C CXMN = SPEKTRALKOEFFIZIENTEN IN DER REIHENFOLGE -C CX00,CX01,CX11,CX02,....CXMNAUFMNAUF -C CXM = FOURIERKOEFFIZIENTEN - nur ein Hilfsfeld -C FELD = FELD DER METEOROLOGISCHEN VARIABLEN -C WSAVE = Working Array fuer Fouriertransformation -C Z = LEGENDREFUNKTIONSWERTE -C -C MNAUF ANZAHL DER FOURIERKOEFFIZIENTEN -C MAXL ANZAHL DER FUER DAS GITTER BENUTZTEN LAENGEN -C MAXB ANZAHL DER FUER DAS GITTER BENOETIGTEN BREITEN -C MLEVEL ANZAHL DER LEVELS, DIE TRANSFORMIERT WERDEN -C - IMPLICIT REAL (A-H,O-Z) - -C FELD DER FOURIERKOEFFIZIENTEN - REAL CXMS(4*(MNAUF+1)) - REAL CXMA(4*(MNAUF+1)) - REAL,ALLOCATABLE :: CXM(:,:) - -C Anzahl der Gitterpunkte pro Breitenkreis des reduzierten -C Gauss'schen Gitters - INTEGER MLAT(MAXB),ISIZE - -C FELD DER LEGENDREPOLYNOME FUER EINE BREITE - REAL Z(MAXB/2,0:((MNAUF+3)*(MNAUF+4))/2) - -C LOGICAL*1 USED(((216*217)/2+1)*160) - - REAL CXMN(0:(MNAUF+1)*(MNAUF+2)-1,MLEVEL) - REAL FELD(MAXL,MLEVEL) - REAL WSAVE(8*MAXB+15,MAXB/2) - INTEGER IFAX(10,MAXB) - REAL W(MAXB) - INTEGER IND(MAXB) - - ALLOCATE(CXM( 4*MAXB,MAXB)) - DO 5 J=1,MAXB/2 - CXMS(1:MLAT(J))=FELD(IND(J)+1:IND(J)+MLAT(J),L) - CALL RFOUFTR(CXMS,WSAVE(1,J),IFAX(:,J),MNAUF,MLAT(J),1) - CXMA(1:MLAT(J))=FELD(MAXL-IND(J)-MLAT(J)+1:MAXL-IND(J),L) - CALL RFOUFTR(CXMA, - *WSAVE(1,J),IFAX(:,J),MNAUF,MLAT(J),1) - DO 4 I=1,2*(MNAUF+1) - CXM(I,J)=CXMS(I)+CXMA(I) - CXM(I,MAXB+1-J)=CXMS(I)-CXMA(I) -4 CONTINUE - 5 CONTINUE - CALL LGTR213(CXMN(0,L),CXM,Z,W,MLAT,MNAUF,MAXB) - - DEALLOCATE(CXM) - - RETURN - END SUBROUTINE GRPHSUB -C - SUBROUTINE LGTR213(CXMN,CXM,Z,W,MLAT,MNAUF,MAXB) - IMPLICIT REAL (A-H,O-Z) - INTEGER MLAT(MAXB) - DIMENSION CXM(0:4*MAXB-1,MAXB) - DIMENSION CXMN(0:2*(((MNAUF+1)*MNAUF)/2+MNAUF)+1) - REAL*8 Z(MAXB/2,0:((MNAUF+3)*(MNAUF+4))/2) - REAL*8 W(MAXB),CR,CI,HILF - LOGICAL EVEN -C -C DIESE ROUTINE BERECHNET DIE KFFKs CXMN -C - LL=0 - LLP=0 - DO 1 I=0,MNAUF - KM=0 - 9 KM=KM+1 - IF(MLAT(KM).LE.2*I) THEN - GOTO 9 - ENDIF - DO 2 J=I,MNAUF - CR=0 - CI=0 - EVEN=MOD(I+J,2).EQ.0 - IF(EVEN) THEN - DO 3 K=KM,MAXB/2 - HILF=W(K)*Z(K,LLP) - CR=CR+CXM(2*I,K)*HILF - CI=CI+CXM(2*I+1,K)*HILF - 3 CONTINUE - ELSE - DO 4 K=KM,MAXB/2 - HILF=W(K)*Z(K,LLP) - CR=CR+CXM(2*I,MAXB+1-K)*HILF - CI=CI+CXM(2*I+1,MAXB+1-K)*HILF - 4 CONTINUE - ENDIF - 5 CXMN(2*LL)=CR - CXMN(2*LL+1)=CI - LL=LL+1 - LLP=LLP+1 - 2 CONTINUE - LLP=LLP+2 - 1 CONTINUE - RETURN - END SUBROUTINE LGTR213 -C - -C - SUBROUTINE RFOUFTR(CXM,TRIGS,IFAX,MNAUF,MAXL,ISIGN) -C BERECHNET DIE FOURIERSUMME MIT EINEM FFT-ALGORITHMUS - IMPLICIT REAL (A-H,O-Z) - DIMENSION CXM(0:2*MAXL-1) - DIMENSION FELD(MAXL),TRIGS(2*MAXL) - DIMENSION WSAVE(MAXAUF) - INTEGER IFAX(10) - - -C NORMIERUNG... - WSAVE(1)=CXM(MAXL-1) - - CXM(1:MAXL)=CXM(0:MAXL-1)/2 - CXM(0)=WSAVE(1)/2 -! CALL CFFTF(MAXL,CXM,WSAVE) - CALL FFT99(CXM,WSAVE,TRIGS,IFAX,1,1,MAXL,1,-1) - RETURN - END SUBROUTINE RFOUFTR - - END MODULE GRTOPH diff --git a/src/jparams.h b/src/jparams.h deleted file mode 100644 index 146a7f0..0000000 --- a/src/jparams.h +++ /dev/null @@ -1,34 +0,0 @@ -C -C Parameters -C - INTEGER JP32, JPLONO, J2NFFT, JPFFT, JPLOOK, JPMAX, JPMAXITER - INTEGER JPMXTRY, JPTRNC, JPK, JPTRP1 - PARAMETER ( JP32 = 32 ) -C -C The following value for JPLONO (2560) will handle regular grids -C from N1 to N720 derived from spectral truncations from T1 to -C T639. -C -Cjdc PARAMETER ( JPLONO = 2560 , J2NFFT = 2 + JPLONO, JPFFT = 12000) - PARAMETER ( JPLONO = 6000 , J2NFFT = 2 + JPLONO, JPFFT = 12000) - PARAMETER ( JPLOOK = 50) - PARAMETER ( JPMAX = 2048 ) - PARAMETER ( JPMAXITER = 10) - PARAMETER ( JPMXTRY = 3 ) - PARAMETER ( JPTRNC = 2047, JPK = (JPTRNC + 1)*(JPTRNC + 4) ) - PARAMETER ( JPTRP1 = (JPTRNC + 1) ) -C - REAL PPEPSA, PPQUART, PPHALF, PPTWO, PP90 - PARAMETER ( PPEPSA = 1.0E-6) - PARAMETER ( PPQUART = 0.25E0) - PARAMETER ( PPHALF = 0.5E0) - PARAMETER ( PPTWO = 2.0E0) - PARAMETER ( PP90 = 90.0E0) -C - REAL PPI - PARAMETER ( PPI = 3.14159265358979 ) -C -C Debug parameters -C - INTEGER NDBG, NDBGLP - COMMON /JDCNDBG/ NDBG, NDBGLP diff --git a/src/phgrreal.f b/src/phgrreal.f deleted file mode 100644 index aa3658c..0000000 --- a/src/phgrreal.f +++ /dev/null @@ -1,553 +0,0 @@ - MODULE PHTOGR - - INTEGER, PARAMETER :: MAXAUF=36000 - - CONTAINS - - SUBROUTINE PHGR213(CXMN,FELD,WSAVE,IFAX,Z,MLAT,MNAUF, - *MAXL,MAXB,MLEVEL) - -C DIE ROUTINE F]HRT EINE TRANSFORMATION EINER -C FELDVARIABLEN VOM PHASENRAUM IN DEN PHYSIKALISCHEN -C RAUM AUF DAS REDUZIERTE GAUSS'SCHE GITTER DURCH -C -C CXMN = SPEKTRALKOEFFIZIENTEN IN DER REIHENFOLGE -C CX00,CX01,CX11,CX02,....CXMNAUFMNAUF -C FELD = FELD DER METEOROLOGISCHEN VARIABLEN -C WSAVE = Working Array fuer Fouriertransformation -C Z = LEGENDREFUNKTIONSWERTE -C -C MNAUF ANZAHL DER FOURIERKOEFFIZIENTEN -C MAXL ANZAHL DER FUER DAS GITTER BENUTZTEN LAENGEN -C MAXB ANZAHL DER FUER DAS GITTER BENOETIGTEN BREITEN -C MLEVEL ANZAHL DER LEVELS, DIE TRANSFORMIERT WERDEN -C - IMPLICIT NONE - -C Anzahl der Gitterpunkte auf jedem Breitenkreis - INTEGER MLAT(MAXB/2) - INTEGER K,MAXL,MAXB,MLEVEL,MNAUF - INTEGER IND(MAXB) - - -C FELD DER LEGENDREPOLYNOME FUER EINE BREITE - REAL Z(0:((MNAUF+3)*(MNAUF+4))/2,MAXB/2) - - REAL CXMN(0:(MNAUF+1)*(MNAUF+2)-1,MLEVEL) - REAL FELD(MAXL,MLEVEL) - REAL WSAVE(8*MAXB+15,MAXB/2) - INTEGER :: IFAX(10,MAXB) - - IND(1)=0 - DO 7 K=2,MAXB/2 - IND(K)=IND(K-1)+MLAT(K-1) -7 CONTINUE - -!$OMP PARALLEL DO SCHEDULE(DYNAMIC) - DO 17 K=1,MAXB/2 - CALL PHSYM(K,IND,CXMN,FELD,Z,WSAVE,IFAX,MLAT, - *MNAUF,MAXL,MAXB,MLEVEL) - -17 CONTINUE -!$OMP END PARALLEL DO - - RETURN - END SUBROUTINE PHGR213 -C -C - SUBROUTINE PHSYM(K,IND,CXMN,FELD,Z,WSAVE,IFAX,MLAT, - *MNAUF,MAXL,MAXB,MLEVEL) - - IMPLICIT NONE - - INTEGER MLAT(MAXB/2) - INTEGER K,L,I,J,LLS,LLPS,LL,LLP,MAXL,MAXB,MLEVEL,MNAUF - INTEGER IND(MAXB) - INTEGER :: IFAX(10,MAXB) - - -C FELD DER FOURIERKOEFFIZIENTEN - REAL :: CXMS(0:MAXAUF-1),CXMA(0:MAXAUF-1) - -C FELD DER LEGENDREPOLYNOME FUER EINE BREITE - REAL Z(0:((MNAUF+3)*(MNAUF+4))/2,MAXB/2) - REAL ACR,ACI,SCR,SCI - - REAL CXMN(0:(MNAUF+1)*(MNAUF+2)-1,MLEVEL) - REAL FELD(MAXL,MLEVEL) - REAL WSAVE(8*MAXB+15,MAXB/2) - - DO 6 L=1,MLEVEL - LL=0 - LLP=0 - DO 1 I=0,MNAUF - SCR=0.D0 - SCI=0.D0 - ACR=0.D0 - ACI=0.D0 - LLS=LL - LLPS=LLP - IF(2*I+1.LT.MLAT(K)) THEN -C Innerste Schleife aufgespalten um if-Abfrage zu sparen - DO 18 J=I,MNAUF,2 - SCR=SCR+Z(LLP,K)*CXMN(2*LL,L) - SCI=SCI+Z(LLP,K)*CXMN(2*LL+1,L) - LL=LL+2 - LLP=LLP+2 -18 CONTINUE - LL=LLS+1 - LLP=LLPS+1 - DO 19 J=I+1,MNAUF,2 - ACR=ACR+Z(LLP,K)*CXMN(2*LL,L) - ACI=ACI+Z(LLP,K)*CXMN(2*LL+1,L) - LL=LL+2 - LLP=LLP+2 -19 CONTINUE - ENDIF - LL=LLS+(MNAUF-I+1) - LLP=LLPS+(MNAUF-I+3) - CXMS(2*I)=SCR+ACR - CXMS(2*I+1)=SCI+ACI - CXMA(2*I)=SCR-ACR - CXMA(2*I+1)=SCI-ACI - 1 CONTINUE -C CALL FOURTR(CXMS,FELD(IND(k)+1,L),WSAVE(:,K),MNAUF, -C *MLAT(K),1) -C CALL FOURTR(CXMA,FELD(MAXL-IND(k)-MLAT(K)+1,L), -C *WSAVE(:,K),MNAUF,MLAT(K),1) - CALL RFOURTR(CXMS,WSAVE(:,K),IFAX(:,K),MNAUF, - *MLAT(K),1) - FELD(IND(k)+1:IND(K)+MLAT(K),L)=CXMS(0:MLAT(K)-1) - CALL RFOURTR(CXMA, - *WSAVE(:,K),IFAX(:,K),MNAUF,MLAT(K),1) - FELD(MAXL-IND(k)-MLAT(K)+1:MAXL-IND(k),L)=CXMA(0:MLAT(K)-1) -C WRITE(*,*) IND+1,FELD(IND+1,L) -6 CONTINUE - - END SUBROUTINE PHSYM - - SUBROUTINE PHGCUT(CXMN,FELD,WSAVE,IFAX,Z, - * MNAUF,MMAX,MAUF,MANF,MAXL,MAXB,MLEVEL) - -C DIE ROUTINE FUEHRT EINE TRANSFORMATION EINER -C FELDVARIABLEN VOM PHASENRAUM IN DEN PHYSIKALISCHEN -C RAUM AUF KUGELKOORDINATEN DURCH. Es kann ein Teilausschnitt -C Der Erde angegeben werden. Diese Routine ist langsamer als -C phgrph -C -C CXMN = SPEKTRALKOEFFIZIENTEN IN DER REIHENFOLGE -C CX00,CX01,CX11,CX02,....CXMNAUFMNAUF -C FELD = FELD DER METEOROLOGISCHEN VARIABLEN -C BREITE = SINUS DER GEOGRAFISCHEN BREITEN -C -C MNAUF ANZAHL DER FOURIERKOEFFIZIENTEN -C MAUF ANZAHL DER LAENGEN UND DER FOURIERKOEFFIZIENTEN -C MANF ANFANG DES LAENGENBEREICHS FUER DAS GITTER, -C AUF DAS INTERPOLIERT WERDEN SOLL -C MAXL ANZAHL DER FUER DAS GITTER BENUTZTEN LAENGEN -C MAXB ANZAHL DER FUER DAS GITTER BENOETIGTEN BREITEN -C MLEVEL ANZAHL DER LEVELS, DIE TRANSFORMIERT WERDEN -C - IMPLICIT REAL (A-H,O-Z) - -C FELD DER FOURIERKOEFFIZIENTEN - -C FELD DER LEGENDREPOLYNOME FUER EINE BREITE - REAL Z(0:((MMAX+3)*(MMAX+4))/2,MAXB) - - DIMENSION CXMN(0:(MMAX+1)*(MMAX+2)-1,MLEVEL) - REAL FELD(MAXL,MAXB,MLEVEL) - DIMENSION WSAVE(4*MAUF+15) - INTEGER:: IFAX(10) - - LOGICAL SYM - -C -C write(*,*)mauf,mnauf,manf,maxl - - - IF(MAUF.LE.MNAUF) WRITE(*,*) 'TOO COARSE LONGITUDE RESOLUTION' - IF((MANF.LT.1).OR.(MAXL.LT.1).OR. - * (MANF.GT.MAUF).OR.(MAXL.GT.MAUF)) THEN - WRITE(*,*) 'WRONG LONGITUDE RANGE',MANF,MAXL - STOP - ENDIF - -C Pruefe, ob Ausgabegitter symmetrisch zum Aequator ist -C Wenn ja soll Symmetrie der Legendrepolynome ausgenutzt werden - IF(MAXB .GT. 4) THEN - SYM=.TRUE. - DO 11 J=5,5 - IF(ABS(ABS(Z(100,J))-ABS(Z(100,MAXB+1-J))).GT.1E-11) - * SYM=.FALSE. -C WRITE(*,*) ABS(Z(100,J)),ABS(Z(100,MAXB+1-J)) -11 CONTINUE - WRITE(*,*) 'Symmetrisch: ',SYM - ELSE - SYM=.FALSE. - ENDIF - - - IF(SYM) THEN -!$OMP PARALLEL DO - DO J=1,(MAXB+1)/2 - CALL PHSYMCUT(J,CXMN,FELD,Z,WSAVE,IFAX, - *MAUF,MNAUF,MAXL,MAXB,MLEVEL,MANF) - - ENDDO -!$OMP END PARALLEL DO - ELSE -!$OMP PARALLEL DO - DO J=1,MAXB - CALL PHGPNS(CXMN,FELD,Z,WSAVE,IFAX, - *J,MNAUF,MAUF,MANF,MAXL,MAXB,MLEVEL) - ENDDO -!$OMP END PARALLEL DO - - ENDIF - - - RETURN - END SUBROUTINE PHGCUT - - SUBROUTINE PHSYMCUT(J,CXMN,FELD,Z,WSAVE,IFAX, - *MAUF,MNAUF,MAXL,MAXB,MLEVEL,MANF) - - IMPLICIT REAL (A-H,O-Z) - -C FELD DER FOURIERKOEFFIZIENTEN - - REAL :: CXM(0:MAXAUF-1),CXMA(0:MAXAUF-1) - - -C FELD DER LEGENDREPOLYNOME FUER EINE BREITE - REAL Z(0:((MNAUF+3)*(MNAUF+4))/2,MAXB) - REAL SCR,SCI,ACR,ACI - - DIMENSION CXMN(0:(MNAUF+1)*(MNAUF+2)-1,MLEVEL) - REAL FELD(MAXL,MAXB,MLEVEL) - DIMENSION WSAVE(4*MAUF+15) - INTEGER :: IFAX(10) - - DO 16 L=1,MLEVEL - LL=0 - LLP=0 - DO 17 I=0,MNAUF - SCR=0.D0 - SCI=0.D0 - ACR=0.D0 - ACI=0.D0 - LLS=LL - LLPS=LLP -C Innerste Schleife aufgespalten um if-Abfrage zu sparen - DO 18 K=I,MNAUF,2 - SCR=SCR+Z(LLP,J)*CXMN(2*LL,L) - SCI=SCI+Z(LLP,J)*CXMN(2*LL+1,L) - LL=LL+2 - LLP=LLP+2 -18 CONTINUE - LL=LLS+1 - LLP=LLPS+1 - DO 19 K=I+1,MNAUF,2 - ACR=ACR+Z(LLP,J)*CXMN(2*LL,L) - ACI=ACI +Z(LLP,J)*CXMN(2*LL+1,L) - LL=LL+2 - LLP=LLP+2 -19 CONTINUE - LL=LLS+MNAUF-I+1 - LLP=LLPS+MNAUF-I+3 - CXM(2*I)=SCR+ACR - CXM(2*I+1)=SCI+ACI - CXMA(2*I)=SCR-ACR - CXMA(2*I+1)=SCI-ACI -17 CONTINUE - - CALL RFOURTR(CXM,WSAVE,IFAX,MNAUF,MAUF,1) - DO 26 I=0,MAXL-1 - IF(MANF+I.LE.MAUF) THEN - FELD(I+1,J,L)=CXM(MANF+I-1) - ELSE - FELD(I+1,J,L)=CXM(MANF-MAUF+I-1) - ENDIF -26 CONTINUE - CALL RFOURTR(CXMA,WSAVE,IFAX,MNAUF,MAUF,1) - DO 36 I=0,MAXL-1 - IF(MANF+I.LE.MAUF) THEN - FELD(I+1,MAXB+1-J,L)=CXMA(MANF+I-1) - ELSE - FELD(I+1,MAXB+1-J,L)=CXMA(MANF-MAUF+I-1) - ENDIF -36 CONTINUE -16 CONTINUE - - END SUBROUTINE PHSYMCUT - - SUBROUTINE PHGPNS(CXMN,FELD,Z,WSAVE,IFAX, - *J,MNAUF,MAUF,MANF,MAXL,MAXB,MLEVEL) - - IMPLICIT NONE - INTEGER,intent(in) :: MNAUF,MAUF,MANF,J,MAXL,MAXB,MLEVEL - REAL :: CXM(0:MAXAUF-1) - REAL,intent(in) :: Z(0:((MNAUF+3)*(MNAUF+4))/2,MAXB) - - REAL,intent(in) :: CXMN(0:(MNAUF+1)*(MNAUF+2)-1,MLEVEL) - - REAL,intent(in) :: WSAVE(4*MAUF+15) - - REAL :: FELD(MAXL,MAXB,MLEVEL) - INTEGER :: IFAX(10) - - INTEGER I,L - - DO L=1,MLEVEL - CALL LEGTR(CXMN(:,L),CXM,Z(:,J),MNAUF,MAUF) - CALL RFOURTR(CXM,WSAVE,IFAX,MNAUF,MAUF,1) - - DO I=0,MAXL-1 - IF(MANF+I.LE.MAUF) THEN - FELD(I+1,J,L)=CXM(MANF+I-1) - ELSE - FELD(I+1,J,L)=CXM(MANF-MAUF+I-1) - ENDIF - ENDDO - ENDDO - END SUBROUTINE PHGPNS -C - SUBROUTINE LEGTR(CXMN,CXM,Z,MNAUF,MAUF) - IMPLICIT NONE - INTEGER MNAUF,MAUF,LL,LLP,I,J - REAL CXM(0:MAXAUF-1) - REAL CXMN(0:(MNAUF+1)*(MNAUF+2)-1) - REAL Z(0:((MNAUF+3)*(MNAUF+4))/2) - REAL CI,CR -C -C DIESE ROUTINE BERECHNET DIE FOURIERKOEFFIZIENTEN CXM -C - LL=0 - LLP=0 - DO 1 I=0,MNAUF - CR=0.D0 - CI=0.D0 - DO 2 J=I,MNAUF - CR=CR+Z(LLP)*CXMN(2*LL) - CI=CI+Z(LLP)*CXMN(2*LL+1) - LL=LL+1 - LLP=LLP+1 - 2 CONTINUE - LLP=LLP+2 - CXM(2*I)=CR - CXM(2*I+1)=CI - 1 CONTINUE - RETURN - END SUBROUTINE LEGTR -C -C -C - SUBROUTINE RFOURTR(CXM,TRIGS,IFAX,MNAUF,MAXL,ISIGN) -C BERECHNET DIE FOURIERSUMME MIT EINEM FFT-ALGORITHMUS - IMPLICIT REAL (A-H,O-Z) - DIMENSION CXM(0:MAXAUF-1) - REAL :: WSAVE(2*MAXL),TRIGS(2*MAXL) - INTEGER IFAX(10) - - DO I=MNAUF+1,MAXL-1 - CXM(2*I)=0.0 - CXM(2*I+1)=0.0 - ENDDO - CALL FFT99(CXM,WSAVE,TRIGS,IFAX,1,1,MAXL,1,1) - DO I=0,MAXL-1 - CXM(I)=CXM(I+1) - ENDDO - - RETURN - END SUBROUTINE RFOURTR -C -C - SUBROUTINE GAULEG(X1,X2,X,W,N) -C BERECHNET DIE GAUSS+SCHEN BREITEN - IMPLICIT REAL (A-H,O-Z) - DIMENSION X(N),W(N) - PARAMETER (EPS=3.D-14) - M=(N+1)/2 - XM=0.5D0*(X2+X1) - XL=0.5D0*(X2-X1) - DO 12 I=1,M - Z=DCOS(3.141592654D0*(I-.25D0)/(N+.5D0)) -1 CONTINUE - P1=1.D0 - P2=0.D0 - DO 11 J=1,N - P3=P2 - P2=P1 - P1=((2.D0*J-1.D0)*Z*P2-(J-1.D0)*P3)/J -11 CONTINUE - PP=N*(Z*P1-P2)/(Z*Z-1.D0) - Z1=Z - Z=Z1-P1/PP - IF(ABS(Z-Z1).GT.EPS)GO TO 1 - X(I)=XM-XL*Z - X(N+1-I)=XM+XL*Z - W(I)=2.D0*XL/((1.D0-Z*Z)*PP*PP) - W(N+1-I)=W(I) -12 CONTINUE - RETURN - END SUBROUTINE GAULEG -C -C - SUBROUTINE PLGNFA(LL,X,Z) -C -C PLGNDN BERECHNET ALLE NORMIERTEN ASSOZIIERTEN -C LEGENDREFUNKTIONEN VON P00(X) BIS PLL(X) -C UND SCHREIBT SIE IN DAS FELD Z -C Die Polynome sind wie im ECMWF indiziert, d.h. -C P00,P10,P11,P20,P21,P22,... -C Ansonsten ist die Routine analog zu PLGNDN -C X IST DER COSINUS DES ZENITWINKELS ODER -C DER SINUS DER GEOGRAFISCHEN BREITE -C - IMPLICIT REAL (A-H,O-Z) - DIMENSION Z(0:((LL+3)*(LL+4))/2) -C - L=LL+2 - I=1 - Z(0)=1.D0 - FACT=1.D0 - POT=1.D0 - SOMX2=DSQRT(1.D0-X*X) - DO 14 J=0,L - DJ=DBLE(J) - IF(J.GT.0) THEN - FACT=FACT*(2.D0*DJ-1.D0)/(2.D0*DJ) - POT=POT*SOMX2 - Z(I)=DSQRT((2.D0*DJ+1.D0)*FACT)*POT - I=I+1 - ENDIF - IF(J.LT.L) THEN - Z(I)=X* - *DSQRT((4.D0*DJ*DJ+8.D0*DJ+3.D0)/(2.D0*DJ+1.D0))*Z(I-1) - I=I+1 - ENDIF - DK=DJ+2.D0 - DO 14 K=J+2,L - DDK=(DK*DK-DJ*DJ) - Z(I)=X*DSQRT((4.D0*DK*DK-1.D0)/DDK)*Z(I-1)- - * DSQRT(((2.D0*DK+1.D0)*(DK-DJ-1.D0)*(DK+DJ-1.D0))/ - * ((2.D0*DK-3.D0)*DDK))*Z(I-2) - DK=DK+1.D0 - I=I+1 -14 CONTINUE - RETURN - END SUBROUTINE PLGNFA - - - SUBROUTINE DPLGND(MNAUF,Z,DZ) -C -C DPLGND BERECHNET DIE ABLEITUNG DER NORMIERTEN ASSOZIIERTEN -C LEGENDREFUNKTIONEN VON P00(X) BIS PLL(X) -C UND SCHREIBT SIE IN DAS FELD DZ -C DIE REIHENFOLGE IST -C P00(X),P01(X),P11(X),P02(X),P12(X),P22(X),..PLL(X) -C - IMPLICIT REAL (A-H,O-Z) - DIMENSION Z(0:((MNAUF+3)*(MNAUF+4))/2) - DIMENSION DZ(0:((MNAUF+2)*(MNAUF+3))/2) -C - IF(Z(0).NE.1.D0) THEN - WRITE(*,*) 'DPLGND: Z(0) must be 1.0' - STOP - ENDIF - - LLP=0 - LLH=0 - DO 1 I=0,MNAUF+1 - DO 2 J=I,MNAUF+1 - IF(I.EQ.J) THEN - WURZELA= - *DSQRT(DBLE((J+1)*(J+1)-I*I)/DBLE(4*(J+1)*(J+1)-1)) - DZ(LLH)=DBLE(J)*WURZELA*Z(LLP+1) - ELSE - WURZELB= - *DSQRT(DBLE((J+1)*(J+1)-I*I)/DBLE(4*(J+1)*(J+1)-1)) - DZ(LLH)= - *DBLE(J)*WURZELB*Z(LLP+1)-DBLE(J+1)*WURZELA*Z(LLP-1) - WURZELA=WURZELB - ENDIF - LLH=LLH+1 - LLP=LLP+1 -2 CONTINUE - LLP=LLP+1 -1 CONTINUE - RETURN - END SUBROUTINE DPLGND - - -* Spectral Filter of Sardeshmukh and Hoskins (1984, MWR) -* MM=Spectral truncation of field -* MMAX= Spectral truncation of filter -* - SUBROUTINE SPFILTER(FELDMN,MM,MMAX) - - IMPLICIT NONE - - INTEGER MM,MMAX,I,J,K,L - REAL FELDMN(0:(MM+1)*(MM+2)-1) - REAL KMAX,SMAX,FAK - - SMAX=0.1 - KMAX=-ALOG(SMAX) - KMAX=KMAX/(float(MMAX)*float(MMAX+1))**2 -c WRITE(*,*)'alogsmax',alog(smax),'KMAX:',KMAX - l=0 - do i=0,MM - do j=i,MM -c write(*,*) i,j,feld(k),feld(k)*exp(-KMAX*(j*(j+1))**2) - if(j .le. MMAX) then -c fak=exp(-KMAX*(j*(j+1))**2) - fak=1.0 - feldmn(2*l)=feldmn(2*l)*fak - feldmn(2*l+1)=feldmn(2*l+1)*fak - else - feldmn(2*l)=0. - feldmn(2*l+1)=0. - endif - l=l+1 - enddo - enddo - END SUBROUTINE SPFILTER - - END MODULE PHTOGR - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/posnam.f b/src/posnam.f deleted file mode 100644 index c5d12d2..0000000 --- a/src/posnam.f +++ /dev/null @@ -1,25 +0,0 @@ - SUBROUTINE POSNAM(KULNAM,CDNAML) -!------------------------------------- - -!--- position in namelist file. -! author: Mats Hamrud, ECMWF - - INTEGER, INTENT(IN) :: KULNAM - CHARACTER*(*), INTENT(IN) :: CDNAML - CHARACTER*120 CLINE - CHARACTER*1 CLTEST - REWIND(KULNAM) - ILEN=LEN(CDNAML) - 102 CONTINUE - CLINE=' ' - READ(KULNAM,'(A)') CLINE - IND1=INDEX(CLINE,'&'//CDNAML) - IF(IND1.EQ.0) GO TO 102 - CLTEST=CLINE(IND1+ILEN+1:IND1+ILEN+1) - IF((LGE(CLTEST,'0').AND.LLE(CLTEST,'9')).OR. - & (LGE(CLTEST,'A').AND.LLE(CLTEST,'Z'))) GO TO 102 - BACKSPACE(KULNAM) - - RETURN - END SUBROUTINE POSNAM - diff --git a/src/preconvert.f90 b/src/preconvert.f90 deleted file mode 100644 index c28610f..0000000 --- a/src/preconvert.f90 +++ /dev/null @@ -1,807 +0,0 @@ - PROGRAM PRECONVERT -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! ! -! PROGRAM PRECONVERT - PREPARES INPUT DATA FOR POP MODEL METEOR- ! -! OLOGICAL PREPROCESSOR ! -! ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! ! -! CALCULATION OF ETAPOINT ON A REGULAR LAMDA/PHI GRID AND WRITING ! -! U,V,ETAPOINT,T,PS,Q,SD,MSL,TCC,10U, 10V, 2T,2D,LSP,CP,SSHF,SSR, ! -! EWSS,NSSS TO AN OUTPUT FILE (GRIB 1 or 2 FORMAT). ! -! ! -! AUTHORS: L. HAIMBERGER, G. WOTAWA, 1994-04 ! -! adapted: A. BECK ! -! 2003-05-11 ! -! L. Haimberger 2006-12 V2.0 ! -! modified to handle arbitrary regular grids ! -! and T799 resolution data ! -! L. Haimberger 2010-03 V4.0 ! -! modified to grib edition 2 fields ! -! and T1279 resolution data ! -! ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! ! -! DESCRIPTION OF NEEDED INPUT: ! -! ! -! UNIT FILE PARAMETER(S) DATA REPRESENTATION ! -! ! -! 11 fort.11 T,U,V regular lamda phi grid ! -! 12 fort.12 D regular lamda phi grid ! -! 13 fort.13 LNSP fort.13 spherical harmonics ! -! 14 fort.14 SD,MSL,TCC,10U, ! -! 10V,2T,2D regular lamda phi grid ! -! 16 fort.16 LSP,CP,SSHF, ! -! SSR,EWSS,NSSS regular lamda phi grid ! -! 17 fort.17 Q regular lamda phi grid ! -! ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! ! -! DESCRIPTION OF OUTPUT: ! -! ! -! UNIT FILE PARAMETER(S) DATA REPRESENTATION ! -! ! -! 15 fort.15 U,V,ETA,T,PS, ! -! Q,SD,MSL,TCC, ! -! 10U,10V,2T,2D, regular lamda phi grid ! -! LSP,CP,SSHF, ! -! SSR,EWSS,NSSS ! -! ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! - - USE PHTOGR - USE GRTOPH - USE FTRAFO - USE RWGRIB2 - USE GRIB_API - - IMPLICIT NONE - - REAL, ALLOCATABLE, DIMENSION (:,:) :: LNPS - REAL, ALLOCATABLE, DIMENSION (:,:) :: Z - REAL, ALLOCATABLE, DIMENSION (:,:,:) :: T, UV , UV2 - REAL, ALLOCATABLE, DIMENSION (:,:,:) :: QA,OM,OMR - REAL, ALLOCATABLE, DIMENSION (:,:,:) :: DIV, ETA,ETAR - REAL, ALLOCATABLE, DIMENSION (:,:) :: DPSDL, DPSDM - REAL, ALLOCATABLE, DIMENSION (:,:,:) :: PS,DPSDT - REAL, ALLOCATABLE, DIMENSION (:,:,:) :: SURF,FLUX,OROLSM - REAL, ALLOCATABLE, DIMENSION (:) :: WSAVE,H,SINL,COSL,WSAVE2 - REAL, ALLOCATABLE, DIMENSION (:) :: BREITE, GBREITE,AK, BK,pv - -! Arrays for Gaussian grid calculations - - REAL :: X1,X2,RMS,MW,SIG,LAM - REAL,ALLOCATABLE :: CUA(:,:,:),CVA(:,:,:) - - REAL, ALLOCATABLE, DIMENSION (:,:) :: P,PP !,P2 - REAL, ALLOCATABLE, DIMENSION (:,:) :: XMN,HILFUV - REAL, ALLOCATABLE, DIMENSION (:) :: LNPMN,LNPMN2,LNPMN3 - REAL, ALLOCATABLE, DIMENSION (:) :: WEIGHT - REAL, ALLOCATABLE, DIMENSION (:,:) :: UGVG - REAL, ALLOCATABLE, DIMENSION (:,:) :: DG, ETAG - REAL, ALLOCATABLE, DIMENSION (:,:) :: GWSAVE - REAL, ALLOCATABLE, DIMENSION (:) :: PSG,HILF - -! end arrays for Gaussian grid calculations - - INTEGER, ALLOCATABLE, DIMENSION (:) :: MLAT,MPSURF,MPFLUX,MPORO,MPAR - INTEGER, ALLOCATABLE :: GIFAX(:,:) - - REAL PI,COSB,DAK,DBK,P00 - REAL URLAR8,JMIN1,LLLAR8,MAXBMIN1,PIR8,DCOSB - - INTEGER I,J,K,L,IERR,M,LTEST,MK,NGI,NGJ - INTEGER MFLUX,MSURF,MORO - INTEGER LUNIT,LUNIT2 - - INTEGER MAXL, MAXB, MLEVEL, LEVOUT,LEVMIN,LEVMAX - INTEGER MOMEGA,MOMEGADIFF,MGAUSS,MSMOOTH, MNAUF,META,METADIFF - INTEGER MDPDETA,METAPAR - REAL RLO0, RLO1, RLA0, RLA1 - CHARACTER*300 MLEVELIST - - INTEGER MAUF, MANF,IFAX(10) - - INTEGER IGRIB(1),iret,ogrib - - CHARACTER*80 FILENAME - - NAMELIST /NAMGEN/ & - MAXL, MAXB, & - MLEVEL,MLEVELIST,MNAUF,METAPAR, & - RLO0, RLO1, RLA0, RLA1, & - MOMEGA,MOMEGADIFF,MGAUSS,MSMOOTH,META,METADIFF,& - MDPDETA - - LTEST=1 - - call posnam (4,'NAMGEN') - read (4,NAMGEN) - - MAUF=INT(360.*(REAL(MAXL)-1.)/(RLO1-RLO0)+0.0001) -! PRINT*, MAUF - - MANF=INT(REAL(MAUF)/360.*(360.+RLO0)+1.0001) - IF(MANF .gt. MAUF) MANF=MANF-MAUF - - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! ALLOCATE VARIABLES ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - ALLOCATE (LNPS(0:(MNAUF+1)*(MNAUF+2)-1,1)) - - ALLOCATE (H(0:(MNAUF+2)*(MNAUF+3)/2)) - - - ALLOCATE (OM(MAXL, MAXB, MLEVEL)) - - ALLOCATE (ETA(MAXL,MAXB,MLEVEL)) - - ALLOCATE (PS(MAXL, MAXB,1),DPSDT(MAXL, MAXB,1)) - - - ALLOCATE (WSAVE(4*MAUF+15),WSAVE2(4*MAUF+15)) - - ALLOCATE (BREITE(MAXB),AK(MLEVEL+1),BK(MLEVEL+1),pv(2*mlevel+2)) - - ALLOCATE (MPAR(2)) - - ALLOCATE (COSL(MAXL),SINL(MAXL)) - - ALLOCATE (CUA(2,4,MLEVEL),CVA(2,4,MLEVEL)) - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! GAUSS STUFF ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - - IF(MGAUSS .EQ. 1) THEN - LUNIT=0 - FILENAME='fort.18' - - call grib_open_file(LUNIT, TRIM(FILENAME),'r') - - call grib_new_from_file(LUNIT,igrib(1), iret) - -! we can close the file - call grib_close_file(LUNIT) - -! call grib_get(igrib(1),'gridType', j) - - NGJ=MNAUF+1 - - ALLOCATE (GWSAVE(8*NGJ+15,NGJ/2)) - ALLOCATE(GIFAX(10,NGJ)) - ALLOCATE (GBREITE(NGJ),WEIGHT(NGJ)) - ALLOCATE (MLAT(NGJ)) - ALLOCATE (P(0:((MNAUF+3)*(MNAUF+4))/2,NGJ/2)) - ALLOCATE (PP(NGJ/2,0:((MNAUF+3)*(MNAUF+4))/2)) - ALLOCATE (Z(0:((MNAUF+3)*(MNAUF+4))/2,MAXB)) - - call grib_get(igrib(1),'numberOfPointsAlongAMeridian', NGJ) - - ! get as a integer - call grib_get(igrib(1),'pl', MLAT) - - NGI=SUM(MLAT) - - call grib_get(igrib(1),'numberOfVerticalCoordinateValues',mk) - - IF(mk/2-1 .ne. MLEVEL) THEN - WRITE(*,*) 'FATAL: Number of model levels',mk, & - ' does not agree with', MLEVEL,' in namelist' - STOP - ENDIF - call grib_get(igrib(1),'pv',pv) - AK=pv(1:1+MLEVEL) - BK=pv(2+MLEVEL:2*MLEVEL+2) - - ALLOCATE (LNPMN(0:(MNAUF+1)*(MNAUF+2)-1)) - ALLOCATE (LNPMN2(0:(MNAUF+1)*(MNAUF+2)-1)) - ALLOCATE (UGVG(NGI, 2*MLEVEL),HILFUV(2*MAXL,2)) - - - ALLOCATE (DPSDL(NGI,1),DPSDM(NGI,1)) - - ALLOCATE (PSG(NGI),HILF(NGI)) - ALLOCATE (UV(MAXL, MAXB, 2*MLEVEL)) -! ALLOCATE (UV2(MAXL, MAXB, 2*MLEVEL)) - - ALLOCATE (XMN(0:(MNAUF+1)*(MNAUF+2)-1, 2*MLEVEL)) - ALLOCATE (DG(NGI,MLEVEL),ETAG(NGI,MLEVEL)) - -! Initialisieren Legendretransformation -! auf das LaT/LON Gitter - - PI=ACOS(-1.D0) -!$OMP PARALLEL DO - DO 20 J=1,MAXB - - BREITE(J)=SIN((RLA1-(J-1.D0)*(RLA1-RLA0)/(MAXB-1))* PI/180.D0) - - CALL PLGNFA(MNAUF,BREITE(J),Z(0,J)) - -20 CONTINUE -!$OMP END PARALLEL DO - -! Avoid possible Pole problem -! IF(RLA0 .EQ. -90.0) BREITE(MAXB)=sin(-89.99*PI/180.d0) -! IF(RLA1 .EQ. 90.0) BREITE(1)=sin(89.99*PI/180.d0) - -! Initialisation of fields for FFT and Legendre transformation -! to Gaussian grid and back to phase space - X1=-1.D0 - X2=1.D0 - CALL GAULEG(X1,X2,GBREITE,WEIGHT,NGJ) - -!$OMP PARALLEL DO PRIVATE(M) - DO J=1,NGJ/2 - CALL PLGNFA(MNAUF,GBREITE(J),P(:,J)) - DO M=0,(MNAUF+3)*(MNAUF+4)/2 - PP(J,M)=P(M,J) - ENDDO - ENDDO -!$OMP END PARALLEL DO - - -! MPAR(1)=152 - FILENAME='fort.12' - CALL READSPECTRAL(FILENAME,LNPMN,MNAUF,1,MLEVEL,(/152/),AK,BK) -! goto 111 - CALL SET99(WSAVE,IFAX,mauf) - CALL PHGCUT(LNPMN,PS,WSAVE,IFAX,Z, & - MNAUF,MNAUF,MAUF,MANF,MAXL,MAXB,1) - CALL STATIS(MAXL,MAXB,1,EXP(PS),RMS,MW,SIG) - WRITE(*,'(A12,3F12.4)') 'STATISTICS: ',RMS,MW,SIG - - DO J=1,NGJ/2 - CALL SET99(GWSAVE(1,J),GIFAX(1,J),MLAT(J)) - ENDDO - CALL PHGR213(LNPMN,HILF,GWSAVE,GIFAX,P,MLAT,MNAUF,NGI,NGJ,1) - PSG=HILF - CALL GRPH213(LNPMN2,PSG,GWSAVE,GIFAX,PP,WEIGHT,MLAT, & - MNAUF,NGI,NGJ,1) - CALL PHGR213(LNPMN2,HILF,GWSAVE,GIFAX,P,MLAT,MNAUF,NGI,NGJ,1) - - - HILF=exp(PSG)-exp(HILF) - - CALL STATIS(NGI,1,1,HILF,RMS,MW,SIG) - WRITE(*,'(A12,3F11.4)') 'STATISTICS: ',RMS,MW,SIG - - PSG=EXP(PSG) - HILF=PSG - CALL STATIS(NGI,1,1,HILF,RMS,MW,SIG) - WRITE(*,'(A12,3F11.4)') 'STATISTICS: ',RMS,MW,SIG - - 111 FILENAME='fort.10' - CALL READSPECTRAL(FILENAME, & - XMN,MNAUF,2*MLEVEL,MLEVEL,(/131,132/),AK,BK) -! Transformieren des Windes auf das Gaussgitter - CALL PHGR213(XMN,UGVG,GWSAVE,GIFAX,P,MLAT,MNAUF,NGI,NGJ,2*MLEVEL) - DO K=1,MLEVEL -! North Pole - CALL JSPPOLE(XMN(:,K),1,MNAUF,.TRUE.,CUA(:,:,K)) - CALL JSPPOLE(XMN(:,MLEVEL+K),1,MNAUF,.TRUE.,CVA(:,:,K)) -! South Pole - CALL JSPPOLE(XMN(:,K),-1,MNAUF,.TRUE.,CUA(:,3:4,K)) - CALL JSPPOLE(XMN(:,MLEVEL+K),-1,MNAUF,.TRUE.,CVA(:,3:4,K)) - ENDDO - - DO K=1,2*MLEVEL - IF(MSMOOTH .ne. 0) CALL SPFILTER(XMN(:,K),MNAUF,MSMOOTH) - ENDDO - CALL PHGCUT(XMN,UV,WSAVE,IFAX,Z, & - MNAUF,MNAUF,MAUF,MANF,MAXL,MAXB,2*MLEVEL) - - - 112 FILENAME='fort.13' - CALL READSPECTRAL(FILENAME,XMN,MNAUF,MLEVEL,MLEVEL,(/155/),AK,BK) -! Transformieren der horizontalen Divergenz auf das Gaussgitter - CALL PHGR213(XMN,DG,GWSAVE,GIFAX,P,MLAT,MNAUF,NGI,NGJ,MLEVEL) - - -! Berechnung des Gradienten des Logarithmus des Bodendrucks -! auf dem Gaussgitter - CALL PHGRAD(LNPMN,DPSDL,DPSDM,GWSAVE,GIFAX,P,H,MLAT,MNAUF,NGI,NGJ,1) - -! Berechnung der Vertikalgeschwindigkeit auf dem Gaussgitter - CALL CONTGL(HILF,DPSDL,DPSDM,DG,UGVG(:,1),UGVG(:,MLEVEL+1), & - GBREITE,ETAG,MLAT,AK,BK,NGI,NGJ,MLEVEL) - - - CALL GRPH213(XMN,ETAG,GWSAVE,GIFAX,PP,WEIGHT,MLAT, & - MNAUF,NGI,NGJ,MLEVEL) - DO K=1,MLEVEL - IF(MSMOOTH .ne. 0) CALL SPFILTER(XMN(:,K),MNAUF,MSMOOTH) - ENDDO - CALL PHGCUT(XMN,ETA,WSAVE,IFAX,Z,MNAUF,MNAUF,MAUF,MANF,MAXL,MAXB,MLEVEL) - - CALL GRPH213(XMN,HILF,GWSAVE,GIFAX,PP,WEIGHT,MLAT, MNAUF,NGI,NGJ,1) - - IF(MSMOOTH .ne. 0) CALL SPFILTER(XMN(:,1),MNAUF,MSMOOTH) - CALL PHGCUT(XMN,DPSDT,WSAVE,IFAX,Z,MNAUF,MNAUF,MAUF,MANF,MAXL,MAXB,1) -! GOTO 114 - - CALL STATIS(MAXL,MAXB,1,DPSDT,RMS,MW,SIG) - WRITE(*,'(A12,3F11.4)') 'STATISTICS DPSDT: ',RMS,MW,SIG - - IF(MOMEGADIFF .ne. 0) THEN -! Berechnung von Omega auf dem Gaussgitter - CALL OMEGA(PSG,DPSDL,DPSDM,DG,UGVG(:,1),UGVG(:,MLEVEL+1), & - GBREITE,ETAG,MLAT,AK,BK,NGI ,NGJ,MLEVEL) - - CALL GRPH213(XMN,ETAG,GWSAVE,GIFAX,PP,WEIGHT,MLAT,& - MNAUF,NGI,NGJ,MLEVEL) - DO K=1,MLEVEL - IF(MSMOOTH .ne. 0) CALL SPFILTER(XMN(:,K),MNAUF,MSMOOTH) - ENDDO - CALL PHGCUT(XMN,OM,WSAVE,IFAX,Z,MNAUF,MNAUF,MAUF,MANF,MAXL,MAXB,MLEVEL) - - ENDIF !MOMEGA - - CALL GRPH213(XMN,PSG,GWSAVE,GIFAX,PP,WEIGHT,MLAT,MNAUF,NGI,NGJ,1) - CALL PHGCUT(XMN,PS,WSAVE,IFAX,Z,MNAUF,MNAUF,MAUF,MANF,MAXL,MAXB,1) - - CALL STATIS(MAXL,MAXB,1,PS,RMS,MW,SIG) - WRITE(*,'(A12,3F11.4)') 'STATISTICS: ',RMS,MW,SIG - - 114 DEALLOCATE(HILF,PSG,DPSDL,DPSDM,ETAG,DG,LNPMN) - -! ALLOCATE (UV(MAXL, MAXB, 2*MLEVEL)) -! CALL GRPH213(XMN,UGVG,GWSAVE,GIFAX,PP,WEIGHT,MLAT, -! *MNAUF,NGI,NGJ,2*MLEVEL) -! DO K=1,2*MLEVEL -! IF(MSMOOTH .ne. 0) CALL SPFILTER(XMN(:,K),MNAUF,MSMOOTH) -! ENDDO -! CALL PHGCUT(XMN,UV,WSAVE,IFAX,Z, -! *MNAUF,MNAUF,MAUF,MANF,MAXL,MAXB,2*MLEVEL) - DEALLOCATE(PP,P,UGVG,MLAT,GBREITE,WEIGHT,GWSAVE,XMN) - -! CALL ETAGAUSS(Z,WSAVE -! *,BREITE,UV,ETA,OM,PS, -! *MAUF,MAXB,MAXL,MANF,MNAUF,MLEVEL,MSMOOTH) - - ELSE - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! READING OF PREPARED METEOROLOGICAL FIELDS ! -! ! -! THE FOLLOWING FIELDS ARE EXPECTED: ! -! ! -! UNIT 11: T,U,V (REGULAR GRID) ! -! UNIT 17: Q (REGULAR GRID) ! -! UNIT 13: D (REGULAR GRID) ! -! UNIT 12: LNSP (SPHERICAL HARMONICS) ! -! UNIT 14: SURFACE DATA (REGULAR GRID) ! -! UNIT 16: FLUX DATA (REGULAR GRID) ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! - ALLOCATE (MLAT(MAXB)) - MLAT=MAXL - ALLOCATE (Z(0:((MNAUF+3)*(MNAUF+4))/2,1)) - ALLOCATE (DPSDL(MAXL,MAXB),DPSDM(MAXL,MAXB)) - ALLOCATE (UV(MAXL, MAXB, 2*MLEVEL),DIV(MAXL,MAXB,MLEVEL)) - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! READING OF SURFACE PRESSURE ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - FILENAME='fort.12' - CALL READSPECTRAL(FILENAME,LNPS,MNAUF,1,MLEVEL,(/152/),AK,BK) - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! READING OF U,V ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! -! OPENING OF UNBLOCKED GRIB FILE -! - FILENAME='fort.10' - CALL READLATLON(FILENAME,UV,MAXL,MAXB,2*MLEVEL,(/131,132/)) - - - PI=ACOS(-1.D0) - DO J=1,MAXB - - BREITE(J)=SIN((RLA1-(J-1.D0)*(RLA1-RLA0)/(MAXB-1))*PI/180.D0) - - ENDDO -! Avoid possible Pole problem -! IF(RLA0 .EQ. -90.0) BREITE(MAXB)=sin(-89.99*PI/180.d0) -! IF(RLA1 .EQ. 90.0) BREITE(1)=sin(89.99*PI/180.d0) - - DO K=1,2*MLEVEL - DO J=1,MAXB - COSB=SQRT(1.0-(BREITE(J))*(BREITE(J))) - IF(RLA0 .EQ. -90.0 .AND. J .EQ. MAXB .OR. & - RLA1 .EQ. 90.0 .AND. J .EQ. 1) then - UV(:,J,K)=UV(:,J,K)/1.D6 - else - UV(:,J,K)=UV(:,J,K)*COSB - endif - ENDDO - ENDDO - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! READING OF LNSP on grid ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -! For debugging only -! FILENAME='LNSPG_G.20060330.600' -! INQUIRE(FILE=FILENAME,EXIST=EX) -! CALL READLATLON(FILENAME,QA, -! *MAXL,MAXB,1,1,(/152/)) - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! READING OF DIVERGENCE ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - IF(META .EQ. 0 .OR. METADIFF .EQ. 1) THEN - FILENAME='fort.13' - CALL READLATLON(FILENAME,DIV,MAXL,MAXB,MLEVEL,(/155/)) - ENDIF - - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! CALCULATION OF ETAPOINT --> TOTAL TIME DERIVATIVE OF ! -! ECMWF VERTICAL COORDINATE ETA MULTIPLIED BY DERIVATIVE ! -! OF PRESSURE IN ETA DIRECTION ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -! Initialisieren Legendretransformation -! auf das LaT/LON Gitter -! Without Gaussian grid calculation Legendre Polynomials are calculated -! only for one latitude to save space - - DO J=1,MAXB - - CALL PLGNFA(MNAUF,BREITE(J),Z(0,1)) - - CALL PHGCUT(LNPS,PS(:,J,1),WSAVE,IFAX,Z,MNAUF,MNAUF,MAUF,MANF,MAXL,1,1) - - - IF(META .EQ. 0 .or. METADIFF .EQ. 1 ) THEN - CALL PHGRACUT(LNPS,DPSDL(:,J),DPSDM(:,J),WSAVE,IFAX,Z,H,MAUF, & - MNAUF,MAXL,1,MANF,1) - ENDIF - ENDDO - - PS=EXP(PS) - -! For debugging only - CALL STATIS(MAXL,MAXB,1,PS(:,:,1),RMS,MW,SIG) - WRITE(*,'(A12,3F11.4)') 'STATISTICS: ',RMS,MW,SIG - - - IF(MOMEGADIFF .ne. 0) THEN - - CALL OMEGA(PS,DPSDL,DPSDM,DIV,UV(:,:,1),UV(:,:,MLEVEL+1), & - BREITE,OM,MLAT,AK,BK,MAXL*MAXB,MAXB,MLEVEL) - ENDIF - - IF(META .EQ. 0 .OR. METADIFF .ne. 0) THEN - DPSDT=PS - CALL CONTGL(DPSDT,DPSDL,DPSDM,DIV,UV(:,:,1),UV(:,:,MLEVEL+1), & - BREITE,ETA,MLAT,AK,BK,MAXL*MAXB,MAXB,MLEVEL) - ENDIF - - ENDIF ! MGAUSS - -! CREATE FILE VERTICAL.EC NEEDED BY POP MODEL - - open(21,file='VERTICAL.EC') - write(21,'(a)') - write(21,'(a)') 'VERTICAL DISCRETIZATION OF POP MODEL' - write(21,'(a)') - write(21,'(i3,a)') MLEVEL,' number of layers' - write(21,'(a)') - write(21,'(a)') '* A(NLEV+1)' - write(21,'(a)') - do 205 i=1,MLEVEL+1 -205 write(21,'(f18.12)') AK(I) - write(21,'(a)') - write(21,'(a)') '* B(NLEV+1)' - write(21,'(a)') - do 210 i=1,MLEVEL+1 -210 write(21,'(f18.12)') BK(I) - close(21) - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! READING OF OMEGA ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - IF(MOMEGA .NE. 0 ) THEN - - - - ALLOCATE (OMR(MAXL, MAXB, MLEVEL)) - - FILENAME='fort.19' - CALL READLATLON(FILENAME,OMR,MAXL,MAXB,MLEVEL,(/135/)) - - IF(MOMEGADIFF .NE. 0 ) THEN - - DO K=1,MLEVEL - CALL STATIS(MAXL,MAXB,1,ETA(:,:,K),RMS,MW,SIG) - WRITE(*,'(A12,I3,3F11.4)') ' ETA: ',K,RMS,MW,SIG - CALL STATIS(MAXL,MAXB,1,OMR(:,:,K),RMS,MW,SIG) - WRITE(*,'(A12,I3,3F11.4)') ' OMEGA: ',K,RMS,MW,SIG - CALL STATIS(MAXL,MAXB,1,OM(:,:,K)-OMR(:,:,K),RMS,MW,SIG) - WRITE(*,'(A12,I3,3F11.4)') 'OMEGA DIFF: ',K,RMS,MW,SIG - ENDDO - - ENDIF - ENDIF - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! READING OF ETA ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - IF(META .NE. 0 ) THEN - - ALLOCATE (ETAR(MAXL, MAXB, MLEVEL)) - - P00=101325. - FILENAME='fort.21' - CALL READLATLON(FILENAME,ETAR,MAXL,MAXB,MLEVEL,(/77/)) - - if(MDPDETA .EQ. 1) THEN - DO K=1,MLEVEL - DAK=AK(K+1)-AK(K) - DBK=BK(K+1)-BK(K) - DO J=1,MAXB - DO I=1,MAXL - ETAR(I,J,K)=2*ETAR(I,J,K)*PS(I,J,1)*(DAK/PS(I,J,1)+DBK)/ & - (DAK/P00+DBK) - IF(K .GT. 1) ETAR(I,J,K)=ETAR(I,J,K)-ETAR(I,J,K-1) - ENDDO - ENDDO - ENDDO - ENDIF - - IF(METADIFF .NE. 0 ) THEN - - DO K=1,MLEVEL - CALL STATIS(MAXL,MAXB,1,ETA(:,:,K),RMS,MW,SIG) - WRITE(*,'(A12,I3,3F11.4)') ' ETA: ',K,RMS,MW,SIG - CALL STATIS(MAXL,MAXB,1,ETAR(:,:,K),RMS,MW,SIG) - WRITE(*,'(A12,I3,3F11.4)') ' ETAR: ',K,RMS,MW,SIG - CALL STATIS(MAXL,MAXB,1,ETA(:,:,K)-ETAR(:,:,K),RMS,MW,SIG) - WRITE(*,'(A12,I3,3F11.4)') 'ETA DIFF: ',K,RMS,MW,SIG - ENDDO - DO K=1,MLEVEL - WRITE(*,'(I3,2F11.4)') K,ETA(1,MAXB/2,K),ETAR(1,MAXB/2,K) - ENDDO - ELSE - ETA=ETAR - ENDIF - ENDIF - - ALLOCATE (T(MAXL, MAXB, MLEVEL)) - ALLOCATE (QA(MAXL, MAXB, MLEVEL)) -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! READING OF T ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! -! OPENING OF UNBLOCKED GRIB FILE -! - FILENAME='fort.11' - CALL READLATLON(FILENAME,T,MAXL,MAXB,MLEVEL,(/130/)) - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! READING OF SPECIFIC HUMIDITY ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - FILENAME='fort.17' - CALL READLATLON(FILENAME,QA,MAXL,MAXB,MLEVEL,(/133/)) - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! TEST READING OF UV from MARS (debug only) ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -! FILENAME='fort.22' -! CALL READLATLON(FILENAME,UV2,MAXL,MAXB,2*MLEVEL,2,(/131,132/)) - - - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! WRITE MODEL LEVEL DATA TO fort.15 ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -! Calculation of etadot in CONTGL needed scaled winds (ucosphi,vcosphi) -! Now we are transforming back to the usual winds. - DO K=1,MLEVEL - DO J=2,MAXB-1 - COSB=SQRT(1.0-(BREITE(J))*(BREITE(J))) - UV(:,J,K)=UV(:,J,K)/COSB - UV(:,J,MLEVEL+K)=UV(:,J,MLEVEL+K)/COSB - ENDDO -! special treatment for poles, if necessary. - DO J=1,MAXB,MAXB-1 - COSB=SQRT(1.0-(BREITE(J))*(BREITE(J))) - if(1.0-BREITE(J)*BREITE(J) .gt. 0 .OR. MGAUSS .NE. 1) then - IF(RLA0 .EQ. -90.0 .AND. J .EQ. MAXB .OR. & - RLA1 .EQ. 90.0 .AND. J .EQ. 1) then - UV(:,J,K)=UV(:,J,K)*1.D6 - UV(:,J,MLEVEL+K)=UV(:,J,MLEVEL+K)*1.D6 - else - UV(:,J,K)=UV(:,J,K)/COSB - UV(:,J,MLEVEL+K)=UV(:,J,MLEVEL+K)/COSB - endif - else - HILFUV(5:MAXL,:)=0. - HILFUV(1:2,:)=0. - IF(J.EQ.MAXB) THEN -! Suedpol - HILFUV(3:4,1)=CUA(:,4,K) - HILFUV(3:4,2)=CVA(:,4,K) - ELSE -! Nordpol - HILFUV(3:4,1)=CUA(:,2,K) - HILFUV(3:4,2)=CVA(:,2,K) - ENDIF - CALL RFOURTR(HILFUV(:,1),WSAVE,IFAX,MAXL/2-1,MAXL,-1) - DO I=0,MAXL-1 - IF(MANF+I.LE.MAXL) THEN - UV(I+1,J,K)=HILFUV(MANF+I,1) - ELSE - UV(I+1,J,K)=HILFUV(MANF-MAXL+I,1) - ENDIF - ENDDO - CALL RFOURTR(HILFUV(:,2),WSAVE,IFAX,MAXL/2-1,MAXL,-1) - DO I=0,MAXL-1 - IF(MANF+I.LE.MAXL) THEN - UV(I+1,J,MLEVEL+K)=HILFUV(MANF+I,2) - ELSE - UV(I+1,J,MLEVEL+K)=HILFUV(MANF-MAXL+I,2) - ENDIF - ENDDO - endif - ENDDO - ENDDO - -! open output file - call grib_open_file(LUNIT,'fort.15','w') - -! we use temperature on lat/lon on model levels as template for model level data - LUNIT2=0 - call grib_open_file(LUNIT2,'fort.11','r') - call grib_new_from_file(LUNIT2,igrib(1), iret) - call grib_close_file(LUNIT2) - - - CALL WRITELATLON(LUNIT,igrib(1),ogrib,UV(:,:,1),MAXL,MAXB,MLEVEL,MLEVELIST,1,(/131/)) - - CALL WRITELATLON(LUNIT,igrib(1),ogrib,UV(:,:,MLEVEL+1),MAXL,MAXB,MLEVEL,MLEVELIST,1,(/132/)) - - IF(MDPDETA .ne. 1 .AND. MGAUSS .EQ. 0 .and. META .eq. 1) THEN - CALL WRITELATLON(LUNIT,igrib(1),ogrib,ETA,MAXL,MAXB,MLEVEL,MLEVELIST,1,(/77/)) - ELSE - CALL WRITELATLON(LUNIT,igrib(1),ogrib,ETA,MAXL,MAXB,MLEVEL,MLEVELIST,1,(/METAPAR/)) - ENDIF - - CALL WRITELATLON(LUNIT,igrib(1),ogrib,T,MAXL,MAXB,MLEVEL,MLEVELIST,1,(/130/)) - - CALL WRITELATLON(LUNIT,igrib(1),ogrib,PS,MAXL,MAXB,1,'1',1,(/134/)) - - call grib_set(igrib(1),"levelType","ml") - call grib_set(igrib(1),"typeOfLevel","hybrid") - CALL WRITELATLON(LUNIT,igrib(1),ogrib,QA,MAXL,MAXB,MLEVEL,MLEVELIST,1,(/133/)) - - - IF(MOMEGA .EQ. 1) THEN - call grib_open_file(LUNIT2,'fort.25','w') - CALL WRITELATLON(LUNIT2,igrib(1),ogrib,OMR,MAXL,MAXB,MLEVEL,MLEVELIST,1,(/135/)) - - IF(MOMEGADIFF .EQ. 1) THEN - - CALL WRITELATLON(LUNIT2,igrib(1),ogrib,DPSDT,MAXL,MAXB,1,'1',1,(/158/)) - - OM=OM-OMR - CALL WRITELATLON(LUNIT2,igrib(1),ogrib,OM,MAXL,MAXB,MLEVEL,MLEVELIST,1,(/001/)) - call grib_close_file(LUNIT2) - ENDIF - ENDIF - - IF(META .EQ. 1 .and. METADIFF .EQ. 1) THEN - call grib_open_file(LUNIT2,'fort.26','w') - CALL WRITELATLON(LUNIT2,igrib(1),ogrib,ETAR,MAXL,MAXB,MLEVEL,MLEVELIST,1,(/135/)) - -! IF(MOMEGADIFF .EQ. 1) THEN - - CALL WRITELATLON(LUNIT2,igrib(1),ogrib,DPSDT,MAXL,MAXB,1,'1',1,(/158/)) - - OM=ETA-ETAR - CALL WRITELATLON(LUNIT2,igrib(1),ogrib,OM,MAXL,MAXB,MLEVEL,MLEVELIST,1,(/001/)) - call grib_close_file(LUNIT2) -! ENDIF - ENDIF - - - call grib_close_file(LUNIT) - - - - 2000 STOP 'SUCCESSFULLY FINISHED CONVERT_PRE: CONGRATULATIONS' - 3000 STOP 'ROUTINE CONVERT_PRE: ERROR' - 9999 stop 'ROUTINE CONVERT_PRE: ERROR' - END - - - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - INTEGER FUNCTION IA (FIELD1,NI,NJ,NK,G) - - IMPLICIT NONE - INTEGER NI,NJ,NK,I,J,K - REAL FIELD1(NI,NJ,NK) - REAL G - REAL RMIN,RMAX,XMAX,A,A1,A2 - - RMAX=FIELD1(1,1,1) - RMIN=FIELD1(1,1,1) - - DO 100 K=1,NK - DO 100 J=1,NJ - DO 100 I=1,NI - IF (FIELD1(I,J,K).GT.RMAX)RMAX=FIELD1(I,J,K) - IF (FIELD1(I,J,K).LT.RMIN)RMIN=FIELD1(I,J,K) -100 CONTINUE - - IF (ABS(RMIN).GT.RMAX.OR.ABS(RMIN).EQ.RMAX) THEN - XMAX=ABS(RMIN) - ELSE - XMAX=RMAX - ENDIF - - IF (XMAX.EQ.0) THEN - IA = 0 - RETURN - ENDIF - - A1=LOG10 ((G/10.d0)/XMAX) - A2=LOG10 ( G/XMAX ) - IF(A1 .gt. A2) THEN - A=A2 - ELSE - A=A1 - ENDIF - - IF (A.GT.0) IA=INT(A) - IF (A.LT.0) IA=INT(A-1.0) - - RETURN - END - - SUBROUTINE STATIS (NI,NJ,NK,PHI,RMS,MW,SIG) - IMPLICIT REAL (A-H,O-Z) - - REAL PHI(NI,NJ,NK),SIG,MW,RMS,P - - N=NI*NJ*NK - - RMS=0. - MW=0. - - DO 10 I=1,NI - DO 10 J=1,NJ - DO 10 K=1,NK - P=PHI(I,J,K) - RMS=RMS+P*P - MW=MW+P -10 CONTINUE - - RMS=SQRT(RMS/N) - MW=MW/N - - IF(RMS*RMS-MW*MW.LT.0.) THEN - SIG=0.0 - ELSE - SIG=SQRT(RMS*RMS-MW*MW) - ENDIF - - RETURN - END - diff --git a/src/rwGRIB2.f90 b/src/rwGRIB2.f90 deleted file mode 100644 index 09ec94e..0000000 --- a/src/rwGRIB2.f90 +++ /dev/null @@ -1,263 +0,0 @@ - MODULE RWGRIB2 - - CONTAINS - - SUBROUTINE READLATLON(FILENAME,FELD,MAXL,MAXB,MLEVEL,MPAR) - - USE GRIB_API - - IMPLICIT NONE - - integer :: ifile - integer :: iret - integer :: n,mk,parid,nm - integer :: i,k - integer,dimension(:),allocatable :: igrib - integer :: numberOfPointsAlongAParallel - integer :: numberOfPointsAlongAMeridian - real, dimension(:), allocatable :: values - integer :: numberOfValues - real,dimension(maxl,maxb,mlevel) :: feld - integer:: maxl,maxb,mlevel,mstride,mpar(:),irest,div,level - integer :: l(size(mpar)) - character*(*):: filename - - call grib_open_file(ifile, TRIM(FILENAME),'r') - - ! count the messages in the file - call grib_count_in_file(ifile,n) - allocate(igrib(n)) - igrib=-1 - - ! Load the messages from the file. - DO i=1,n - call grib_new_from_file(ifile,igrib(i), iret) - END DO - - ! we can close the file - call grib_close_file(ifile) - - nm=size(mpar) - div=mlevel/nm - l=0 - - ! Loop on all the messages in memory - iloop: DO i=1,n -! write(*,*) 'processing message number ',i - ! get as a integer - call grib_get(igrib(i),'numberOfPointsAlongAParallel', & - numberOfPointsAlongAParallel) - - ! get as a integer - call grib_get(igrib(i),'numberOfPointsAlongAMeridian', & - numberOfPointsAlongAMeridian) - - call grib_get(igrib(i),'numberOfVerticalCoordinateValues',mk) - - call grib_get_size(igrib(i),'values',numberOfValues) -! write(*,*) 'numberOfValues=',numberOfValues - - allocate(values(numberOfValues), stat=iret) - ! get data values - call grib_get(igrib(i),'values',values) - - call grib_get(igrib(i),'paramId',parid) - call grib_get(igrib(i),'level',level) - - kloop: do k=1,nm - if(parid .eq. mpar(k)) then -! l(k)=l(k)+1 - feld(:,:,(k-1)*div+level)=reshape(values,(/maxl,maxb/)) -! print*,(k-1)*div+l(k),parid - exit kloop - endif - enddo kloop - if(k .gt. nm .and. parid .ne. mpar(nm)) then - write(*,*) k,nm,parid,mpar(nm) - write(*,*) 'ERROR readlatlon: parameter ',parid,'is not',mpar - stop - endif - -! print*,i - END DO iloop - write(*,*) 'readlatlon: ',i-1,' records read' - - DO i=1,n - call grib_release(igrib(i)) - END DO - - deallocate(values) - deallocate(igrib) - - END SUBROUTINE READLATLON - - SUBROUTINE WRITELATLON(iunit,igrib,ogrib,FELD,MAXL,MAXB,MLEVEL,& - MLEVELIST,MSTRIDE,MPAR) - - USE GRIB_API - - IMPLICIT NONE - - INTEGER IFIELD,MLEVEL,MNAUF,I,J,K,L,MSTRIDE,IERR,JOUT - INTEGER MPAR(MSTRIDE),MAXL,MAXB,LEVMIN,LEVMAX - INTEGER IUNIT,igrib,ogrib - REAL ZSEC4(MAXL*MAXB) - REAL FELD(MAXL,MAXB,MLEVEL) - CHARACTER*(*) MLEVELIST - INTEGER ILEVEL(MLEVEL),MLINDEX(MLEVEL+1),LLEN - - ! parse MLEVELIST - - LLEN=len(trim(MLEVELIST)) - if(index(MLEVELIST,'to') .ne. 0 .or. index(MLEVELIST,'TO') .ne. 0) THEN - i=index(MLEVELIST,'/') - read(MLEVELIST(1:i-1),*) LEVMIN - i=index(MLEVELIST,'/',.true.) - read(MLEVELIST(i+1:LLEN),*) LEVMAX - l=0 - do i=LEVMIN,LEVMAX - l=l+1 - ILEVEL(l)=i - enddo - else - l=1 - MLINDEX(1)=0 - do i=1,LLEN - if(MLEVELIST(i:i) .eq. '/') THEN - l=l+1 - MLINDEX(l)=i - endif - enddo - MLINDEX(l+1)=LLEN+1 - do i=1,l - read(MLEVELIST(MLINDEX(i)+1:MLINDEX(i+1)-1),*) ILEVEL(i) - enddo - endif - - DO k=1,l - call grib_set(igrib,"level",ILEVEL(k)) - DO j=1,MSTRIDE - call grib_set(igrib,"paramId",MPAR(j)) -! if(MPAR(j) .eq. 87) then -! call grib_set(igrib,"shortName","etadot") -! call grib_set(igrib,"units","Pa,s**-1") -! endif -! if(MPAR(j) .eq. 77) then -! call grib_set(igrib,"shortName","etadot") -! call grib_set(igrib,"units","s**-1") -! endif - if(l .ne. mlevel) then - zsec4(1:maxl*maxb)=RESHAPE(FELD(:,:,ILEVEL(k)),(/maxl*maxb/)) - else - zsec4(1:maxl*maxb)=RESHAPE(FELD(:,:,k),(/maxl*maxb/)) - endif - call grib_set(igrib,"values",zsec4) - - call grib_write(igrib,iunit) - - ENDDO - ENDDO - - - - END SUBROUTINE WRITELATLON - - SUBROUTINE READSPECTRAL(FILENAME,CXMN,MNAUF,MLEVEL,& - MAXLEV,MPAR,A,B) - - USE GRIB_API - - IMPLICIT NONE - - - integer :: ifile - integer :: iret - integer :: n,mk,div,nm,k - integer :: i,j,parid - integer,dimension(:),allocatable :: igrib - real, dimension(:), allocatable :: values - integer :: numberOfValues,maxlev - REAL :: A(MAXLEV+1),B(MAXLEV+1),pv(2*MAXLEV+2) - REAL:: CXMN(0:(MNAUF+1)*(MNAUF+2)-1,MLEVEL) -integer:: maxl,maxb,mlevel,mstride,mpar(:),mnauf,ioffset,ipar,ilev,l(size(mpar)) -character*(*):: filename - - call grib_open_file(ifile, TRIM(FILENAME),'r') - - ! count the messages in the file - call grib_count_in_file(ifile,n) - allocate(igrib(n)) - igrib=-1 - - ! Load the messages from the file. - DO i=1,n - call grib_new_from_file(ifile,igrib(i), iret) - END DO - - ! we can close the file - call grib_close_file(ifile) - - l=0 - ! Loop on all the messages in memory - iloop: DO i=1,n - ! write(*,*) 'processing message number ',i - ! get as a integer - call grib_get(igrib(i),'pentagonalResolutionParameterJ', j) - - call grib_get_size(igrib(i),'values',numberOfValues) - ! write(*,*) 'numberOfValues=',numberOfValues - - call grib_get(igrib(i),'numberOfVerticalCoordinateValues',mk) - - call grib_get(igrib(i),'level',ilev) - - - - call grib_get(igrib(i),'pv',pv) - - allocate(values(numberOfValues), stat=iret) - ! get data values - call grib_get(igrib(i),'values',values) - -! IOFFSET=mod(i-1,MSTRIDE)*(mk/2-1) -! CXMN(:,IOFFSET+ilev)=values(1:(MNAUF+1)*(MNAUF+2)) - - call grib_get(igrib(i),'paramId',parid) - nm=size(mpar) - div=mlevel/nm - kloop: do k=1,nm - if(parid .eq. mpar(k)) then - l(k)=l(k)+1 - cxmn(:,(k-1)*div+l(k))=values(1:(MNAUF+1)*(MNAUF+2)) -! print*,(k-1)*div+l(k),parid - exit kloop - endif - - enddo kloop - if(k .gt. nm .and. parid .ne. mpar(nm)) then - write(*,*) k,nm,parid,mpar(nm) - write(*,*) 'ERROR readspectral: parameter ',parid,'is not',mpar - stop - endif - -! print*,i - - END DO iloop - - write(*,*) 'readspectral: ',i-1,' records read' - - DO i=1,n - call grib_release(igrib(i)) - END DO - - deallocate(values) - deallocate(igrib) - - - - A=pv(1:1+MAXLEV) - B=pv(2+MAXLEV:2*MAXLEV+2) - - END SUBROUTINE READSPECTRAL - - END MODULE RWGRIB2 diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/_templates/compilejob.temp b/templates/compilejob.temp similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/_templates/compilejob.temp rename to templates/compilejob.temp diff --git a/python/pythontest/TestInstallTar/flex_extract_v7.1/_templates/ecmwf_grib1_table_128 b/templates/ecmwf_grib1_table_128 similarity index 100% rename from python/pythontest/TestInstallTar/flex_extract_v7.1/_templates/ecmwf_grib1_table_128 rename to templates/ecmwf_grib1_table_128 diff --git a/templates/job.temp b/templates/job.temp new file mode 100644 index 0000000..43becc4 --- /dev/null +++ b/templates/job.temp @@ -0,0 +1,76 @@ +#!/bin/ksh + +# ON ECGB: +# start with ecaccess-job-submit -queueName ecgb NAME_OF_THIS_FILE on gateway server +# start with sbatch NAME_OF_THIS_FILE directly on machine + +#SBATCH --workdir=/scratch/ms/at/km4a +#SBATCH --qos=normal +#SBATCH --job-name=flex_ecmwf +#SBATCH --output=flex_ecmwf.%j.out +#SBATCH --error=flex_ecmwf.%j.out +#SBATCH --mail-type=FAIL +#SBATCH --time=12:00:00 + +## CRAY specific batch requests +##PBS -N flex_ecmwf +##PBS -q np +##PBS -S /usr/bin/ksh +## -o /scratch/ms/spatlh00/lh0/flex_ecmwf.$PBS_JOBID.out +## job output is in .ecaccess_DO_NOT_REMOVE +##PBS -j oe +##PBS -V +##PBS -l EC_threads_per_task=24 +##PBS -l EC_memory_per_task=32000MB + +set -x +export VERSION=7.1 +case $HOST in + *ecg*) + module load python + module unload grib_api + module unload emos + module load grib_api/1.14.5 + module load emos/437-r64 + export PATH=${PATH}:${HOME}/flex_extract_v7.1/source/python + ;; + *cca*) + module switch PrgEnv-cray PrgEnv-intel + module load grib_api + module load emos + module load python + export SCRATCH=$TMPDIR + export PATH=${PATH}:${HOME}/flex_extract_v7.1/source/python + ;; +esac + +cd $SCRATCH +mkdir -p python$$ +cd python$$ + +export CONTROL=CONTROL + +cat >$CONTROL<<EOF +EOF + + +submit.py --controlfile=$CONTROL --inputdir=./work --outputdir=./work 1> prot 2>&1 + +if [ $? -eq 0 ] ; then + l=0 + for muser in `grep -i MAILOPS $CONTROL`; do + if [ $l -gt 0 ] ; then + mail -s flex.${HOST}.$$ $muser <prot + fi + l=$(($l+1)) + done +else + l=0 + for muser in `grep -i MAILFAIL $CONTROL`; do + if [ $l -gt 0 ] ; then + mail -s "ERROR! flex.${HOST}.$$" $muser <prot + fi + l=$(($l+1)) + done +fi + -- GitLab